OTOWNIF.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066
  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 : OTOWNIF.CPP
  21. //Description : Town interface routines
  22. #include <OINFO.h>
  23. #include <OBOX.h>
  24. #include <OVGA.h>
  25. #include <OSYS.h>
  26. #include <OHELP.h>
  27. #include <OSPY.h>
  28. #include <OSTR.h>
  29. #include <OFONT.h>
  30. #include <OMOUSE.h>
  31. #include <OVBROWIF.h>
  32. #include <OGAME.h>
  33. #include <ONATION.h>
  34. #include <OBUTT3D.h>
  35. #include <OIMGRES.h>
  36. #include <ORAWRES.h>
  37. #include <ORACERES.h>
  38. #include <OWORLD.h>
  39. #include <OUNIT.h>
  40. #include <OTOWN.h>
  41. #include <OREMOTE.h>
  42. #include <OSE.h>
  43. #include <OSERES.h>
  44. #include <OBUTTCUS.h>
  45. //------------- Define coordinations -----------//
  46. enum { RACE_BROWSE_X1 = INFO_X1,
  47. RACE_BROWSE_Y1 = INFO_Y1+48,
  48. RACE_BROWSE_X2 = INFO_X2,
  49. RACE_BROWSE_Y2 = RACE_BROWSE_Y1+130,
  50. };
  51. enum { BUTTON_X1 = INFO_X1,
  52. BUTTON_Y1 = RACE_BROWSE_Y2+28,
  53. BUTTON_X2 = INFO_X2,
  54. BUTTON_Y2 = BUTTON_Y1+50,
  55. };
  56. //---------- Define constant ------------//
  57. enum { TOWN_MENU_MAIN,
  58. TOWN_MENU_TRAIN,
  59. TOWN_MENU_SPY,
  60. TOWN_MENU_VIEW_SECRET,
  61. TOWN_MENU_SET_AUTO_COLLECT_TAX,
  62. TOWN_MENU_SET_AUTO_GRANT,
  63. };
  64. #define BUTTON_LOYALTY_COUNT 8
  65. #define COUNT_BUTTON_OFFSET_X 165
  66. #define COUNT_BUTTON_OFFSET_Y 5
  67. #define COUNT_BUTTON_WIDTH 32
  68. #define COUNT_BUTTON_HEIGHT 32
  69. //----------- Define static variables ----------//
  70. static VBrowseIF browse_race, browse_spy;
  71. static Button3D button_recruit, button_train, button_tax, button_grant;
  72. static Button3D button_spy, button_cancel, button_spy_mobilize,
  73. button_spy_reward, button_spy_action, button_spy_view_secret;
  74. static Button3D button_cancel_training;
  75. static ButtonCustom button_cancel3;
  76. static Button button_loyalty_array[BUTTON_LOYALTY_COUNT];
  77. static Button button_loyalty_disabled;
  78. static Button button_cancel2;
  79. static ButtonCustom button_skill[MAX_TRAINABLE_SKILL];
  80. static ButtonCustom button_queue_skill[MAX_TRAINABLE_SKILL];
  81. static short browse_race_recno=1, browse_race_town_recno=0; // the town which the browse_race displays its info
  82. static short recruit_race_count;
  83. static short spy_count;
  84. static short last_town_recno=0, last_rebel_recno=0;
  85. static char last_has_linked_own_camp;
  86. static char town_menu_mode=TOWN_MENU_MAIN;
  87. static char disable_refresh=0;
  88. static short action_spy_recno; // recno of the spy that is doing the bribing or viewing secret reports of other nations
  89. //-------- Define static class member var ------//
  90. short Town::if_town_recno = 0;
  91. //----------- Define static functions ----------//
  92. static int race_filter(int recNo=0);
  93. static int spy_filter(int recNo=0);
  94. static void put_race_rec(int recNo, int x, int y, int refreshFlag);
  95. static void put_spy_rec(int recNo, int x, int y, int refreshFlag);
  96. // ###### begin Gilbert 12/9 ########//
  97. static void i_disp_skill_button(ButtonCustom *button, int);
  98. static void i_disp_queue_skill_button(ButtonCustom *button, int);
  99. // ###### end Gilbert 12/9 ########//
  100. //--------- Begin of function Town::disp_info ---------//
  101. //
  102. void Town::disp_info(int refreshFlag)
  103. {
  104. if_town_recno = town_recno;
  105. if( town_recno != last_town_recno ||
  106. (refreshFlag==INFO_REPAINT && !disable_refresh) )
  107. {
  108. if( town_recno != last_town_recno )
  109. browse_race_recno = 1;
  110. town_menu_mode = TOWN_MENU_MAIN;
  111. last_town_recno = town_recno;
  112. }
  113. //-----------------------------------------//
  114. int needRepaint=0;
  115. if( last_rebel_recno != rebel_recno )
  116. {
  117. last_rebel_recno = rebel_recno;
  118. needRepaint = 1;
  119. }
  120. if( last_has_linked_own_camp != has_linked_own_camp )
  121. {
  122. last_has_linked_own_camp = has_linked_own_camp;
  123. needRepaint = 1;
  124. }
  125. if( needRepaint && refreshFlag == INFO_UPDATE )
  126. {
  127. info.disp();
  128. return;
  129. }
  130. //-----------------------------------//
  131. switch( town_menu_mode )
  132. {
  133. case TOWN_MENU_MAIN:
  134. disp_main_menu(refreshFlag);
  135. break;
  136. case TOWN_MENU_TRAIN:
  137. disp_train_menu(refreshFlag);
  138. break;
  139. case TOWN_MENU_SPY:
  140. disp_spy_menu(refreshFlag);
  141. break;
  142. case TOWN_MENU_VIEW_SECRET:
  143. spy_array.disp_view_secret_menu(action_spy_recno, refreshFlag);
  144. break;
  145. case TOWN_MENU_SET_AUTO_COLLECT_TAX:
  146. if( refreshFlag == INFO_REPAINT )
  147. disp_auto_menu(1);
  148. break;
  149. case TOWN_MENU_SET_AUTO_GRANT:
  150. if( refreshFlag == INFO_REPAINT )
  151. disp_auto_menu(0);
  152. break;
  153. }
  154. }
  155. //----------- End of function Town::disp_info -----------//
  156. //--------- Begin of function Town::detect_info ---------//
  157. //
  158. void Town::detect_info()
  159. {
  160. if_town_recno = town_recno;
  161. switch( town_menu_mode )
  162. {
  163. case TOWN_MENU_MAIN:
  164. detect_main_menu();
  165. break;
  166. case TOWN_MENU_TRAIN:
  167. detect_train_menu();
  168. break;
  169. case TOWN_MENU_SPY:
  170. detect_spy_menu();
  171. break;
  172. case TOWN_MENU_VIEW_SECRET:
  173. if( spy_array.detect_view_secret_menu(action_spy_recno, nation_recno) )
  174. {
  175. town_menu_mode = TOWN_MENU_MAIN;
  176. info.disp();
  177. }
  178. break;
  179. case TOWN_MENU_SET_AUTO_COLLECT_TAX:
  180. detect_auto_menu(1);
  181. break;
  182. case TOWN_MENU_SET_AUTO_GRANT:
  183. detect_auto_menu(0);
  184. break;
  185. }
  186. }
  187. //----------- End of function Town::detect_info -----------//
  188. //--------- Begin of function Town::disp_main_menu ---------//
  189. //
  190. void Town::disp_main_menu(int refreshFlag)
  191. {
  192. static short lastTownNationRecno;
  193. //--- if the town's owner nation has just been changed ---//
  194. if( lastTownNationRecno != nation_recno )
  195. {
  196. lastTownNationRecno = nation_recno;
  197. info.disp();
  198. return;
  199. }
  200. //--------- display basic info --------//
  201. disp_basic_info(refreshFlag);
  202. //---------- paint controls -----------//
  203. if( refreshFlag == INFO_REPAINT )
  204. {
  205. recruit_race_count = race_filter();
  206. //------ display browser field description -------//
  207. int x=RACE_BROWSE_X1+2;
  208. int y=RACE_BROWSE_Y1-23;
  209. vga.d3_panel_up( RACE_BROWSE_X1, y, RACE_BROWSE_X2, RACE_BROWSE_Y1-3 );
  210. font_san.put( x+2 , y+4, "Population" );
  211. font_san.put( x+70 , y+4, "Peasants" );
  212. if( nation_recno ) // only display loyalty if this town is controlled by a nation
  213. font_san.put( x+132, y+4, "Loyalty" );
  214. else
  215. {
  216. #ifdef GERMAN
  217. font_san.put( x+128, y+4, "Resistance" );
  218. #else
  219. font_san.put( x+132, y+4, "Resistance" );
  220. #endif
  221. }
  222. //------------ create browser ------------//
  223. browse_race.init( RACE_BROWSE_X1, RACE_BROWSE_Y1, RACE_BROWSE_X2, RACE_BROWSE_Y2,
  224. 0, 25, recruit_race_count, put_race_rec );
  225. browse_race.open(browse_race_recno);
  226. browse_race_town_recno = town_recno; // the town which browse_race displays
  227. //---------- paint total section ----------//
  228. vga.d3_panel_up( RACE_BROWSE_X1, RACE_BROWSE_Y2+3, RACE_BROWSE_X2, RACE_BROWSE_Y2+23 );
  229. font_san.put( RACE_BROWSE_X1+5, RACE_BROWSE_Y2+7, "Total" );
  230. font_san.put( RACE_BROWSE_X1+128, RACE_BROWSE_Y2+7, "Avg" );
  231. }
  232. else
  233. {
  234. //---------- update controls -----------//
  235. if( recruit_race_count != race_filter() )
  236. {
  237. info.disp();
  238. return;
  239. }
  240. browse_race.update();
  241. }
  242. browse_race_recno = browse_race.recno();
  243. //----------- display total -----------//
  244. font_mid.put( RACE_BROWSE_X1+52, RACE_BROWSE_Y2+6, population, 1 );
  245. font_mid.put( RACE_BROWSE_X1+94, RACE_BROWSE_Y2+6, jobless_population, 1 );
  246. if( nation_recno )
  247. font_mid.put( RACE_BROWSE_X1+165, RACE_BROWSE_Y2+6, average_loyalty(), 1 );
  248. else
  249. font_mid.put( RACE_BROWSE_X1+165, RACE_BROWSE_Y2+6, average_resistance(nation_array.player_recno), 1 );
  250. //------ if this town is controlled by a rebel group -----//
  251. int x=BUTTON_X1, y=BUTTON_Y1;
  252. if( rebel_recno )
  253. {
  254. if( refreshFlag == INFO_REPAINT )
  255. font_san.d3_put( BUTTON_X1, y-1, BUTTON_X2, y+19, "Controlled by Rebels" );
  256. y+=23;
  257. }
  258. //----------- create the paint button ----------//
  259. if( nation_recno==nation_array.player_recno )
  260. {
  261. if( refreshFlag == INFO_REPAINT )
  262. {
  263. button_recruit.paint( BUTTON_X1, y, 'A', "RECRUIT" );
  264. if( has_linked_own_camp )
  265. {
  266. button_train.paint( BUTTON_X1+BUTTON_ACTION_WIDTH, y, 'A', "TRAIN" );
  267. button_tax.paint( BUTTON_X1+BUTTON_ACTION_WIDTH*2, y, 'A', "COLLTAX" );
  268. button_grant.paint( BUTTON_X1+BUTTON_ACTION_WIDTH*3, y, 'A', "GRANT" );
  269. disp_auto_loyalty();
  270. }
  271. else
  272. {
  273. button_train.reset();
  274. button_tax.reset();
  275. button_grant.reset();
  276. }
  277. #ifdef DEBUG
  278. if(debug2_enable_flag)
  279. {
  280. font_san.d3_put( INFO_X1, INFO_Y2-30, INFO_X2, INFO_Y2, "" );
  281. font_san.field( INFO_X1+10, INFO_Y2-20, " ", INFO_X1+20, town_recno, 1, INFO_X2-10, refreshFlag);
  282. font_san.field( INFO_X1+40, INFO_Y2-20, " ", INFO_X1+50, loc_x1, 1, INFO_X2-10, refreshFlag);
  283. font_san.field( INFO_X1+70, INFO_Y2-20, " ", INFO_X1+80, loc_y1, 1, INFO_X2-10, refreshFlag);
  284. font_san.field( INFO_X1+100, INFO_Y2-20, " ", INFO_X1+110, ai_link_checked, 1, INFO_X2-10, refreshFlag);
  285. }
  286. #endif
  287. }
  288. if( has_linked_own_camp ) // a whole row is used for displaying buttons, so additional buttons will be displayed in the next row
  289. y += BUTTON_ACTION_HEIGHT;
  290. else
  291. x += BUTTON_ACTION_WIDTH; // only one button "Recruit", new button displayed next to it.
  292. //-------- enable/disable the train button -----------//
  293. int raceId = race_filter(browse_race.recno());
  294. if( can_recruit(raceId) )
  295. button_recruit.enable();
  296. else
  297. button_recruit.disable();
  298. if( button_train.init_flag )
  299. {
  300. if( can_train(raceId) )
  301. button_train.enable();
  302. else
  303. button_train.disable();
  304. }
  305. if( button_tax.init_flag )
  306. {
  307. // ###### patch begin Gilbert 5/8 ######//
  308. // if( average_loyalty() >= 1 )
  309. if( average_loyalty() > COLLECT_TAX_LOYALTY_DECREASE )
  310. // ###### end begin Gilbert 5/8 ######//
  311. button_tax.enable();
  312. else
  313. button_tax.disable();
  314. }
  315. if( button_grant.init_flag )
  316. {
  317. if( nation_array[nation_recno]->cash > 0 )
  318. button_grant.enable();
  319. else
  320. button_grant.disable();
  321. }
  322. //--------- display train info --------//
  323. if( train_unit_recno ) // display the progress of the current training process
  324. disp_train_info(refreshFlag);
  325. }
  326. //------ grant to an independent town ------//
  327. else if( nation_array.player_recno &&
  328. can_grant_to_non_own_town(nation_array.player_recno) )
  329. {
  330. if( refreshFlag == INFO_REPAINT )
  331. button_grant.paint( BUTTON_X1, y, 'A', "GRANT2" );
  332. if( button_grant.init_flag )
  333. {
  334. if( nation_array[nation_array.player_recno]->cash > 0 )
  335. button_grant.enable();
  336. else
  337. button_grant.disable();
  338. }
  339. x += BUTTON_ACTION_WIDTH;
  340. }
  341. //---------- display the spy button ----------//
  342. int spyFlag = spy_filter() > 0;
  343. if( refreshFlag == INFO_REPAINT )
  344. {
  345. if( spyFlag ) // only display the spy button for non-player towns
  346. button_spy.paint( x, y, 'A', "SPYMENU" );
  347. else
  348. button_spy.reset();
  349. }
  350. else
  351. {
  352. if( spyFlag != button_spy.init_flag ) // if the button availability has just changed
  353. {
  354. if(spyFlag) // only display the spy button for non-player towns
  355. button_spy.paint( x, y, 'A', "SPYMENU" );
  356. else // remove the button from the screen
  357. button_spy.hide();
  358. }
  359. }
  360. //-------- display debug info ----------//
  361. if( sys.debug_session || sys.testing_session )
  362. disp_debug_resistance(refreshFlag);
  363. }
  364. //----------- End of function Town::disp_main_menu -----------//
  365. //--------- Begin of function Town::disp_auto_loyalty ---------//
  366. //
  367. void Town::disp_auto_loyalty()
  368. {
  369. if( auto_collect_tax_loyalty )
  370. {
  371. vga_front.bar( button_tax.x1+8, button_tax.y1+10, button_tax.x2-12, button_tax.y2-15, V_WHITE );
  372. vga_front.rect( button_tax.x1+8, button_tax.y1+10, button_tax.x2-12, button_tax.y2-15, 1, V_BLACK );
  373. font_mid.center_put( button_tax.x1+8, button_tax.y1+10, button_tax.x2-12, button_tax.y2-15,
  374. m.format(auto_collect_tax_loyalty) );
  375. }
  376. if( auto_grant_loyalty )
  377. {
  378. vga_front.bar( button_grant.x1+8, button_grant.y1+10, button_grant.x2-12, button_grant.y2-15, V_WHITE );
  379. vga_front.rect( button_grant.x1+8, button_grant.y1+10, button_grant.x2-12, button_grant.y2-15, 1, V_BLACK );
  380. font_mid.center_put( button_grant.x1+8, button_grant.y1+10, button_grant.x2-12, button_grant.y2-15,
  381. m.format(auto_grant_loyalty) );
  382. }
  383. }
  384. //----------- End of function Town::disp_auto_loyalty -----------//
  385. //--------- Begin of function Town::detect_main_menu ---------//
  386. //
  387. void Town::detect_main_menu()
  388. {
  389. //--- detect clicking on the name area to center the map on it ---//
  390. if( mouse.single_click(INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+21) )
  391. {
  392. world.go_loc( center_x, center_y );
  393. return;
  394. }
  395. //-------- detect browsers ---------//
  396. if( browse_race.detect() )
  397. {
  398. browse_race_recno = browse_race.recno();
  399. // ##### begin patch Gilbert 21/1 #######//
  400. if( sys.debug_session || sys.testing_session )
  401. disp_debug_resistance(INFO_UPDATE);
  402. // ##### end patch Gilbert 21/1 #######//
  403. }
  404. if( button_spy.detect() ) // switch to the spy menu
  405. {
  406. town_menu_mode = TOWN_MENU_SPY;
  407. disable_refresh = 1; // static var for disp_info() only
  408. info.disp();
  409. disable_refresh = 0;
  410. return;
  411. }
  412. //----- detect granting to an independent town ---//
  413. if( nation_array.player_recno &&
  414. can_grant_to_non_own_town(nation_array.player_recno) )
  415. {
  416. if( button_grant.detect() )
  417. {
  418. se_ctrl.immediate_sound("TURN_ON");
  419. grant_to_non_own_town(nation_array.player_recno, COMMAND_PLAYER);
  420. }
  421. }
  422. //---------- buttons for player town only --------//
  423. if( nation_recno!=nation_array.player_recno )
  424. return;
  425. //------ update button status ------//
  426. if( browse_race.recno() > race_filter() )
  427. return;
  428. int raceId = race_filter(browse_race.recno());
  429. if( can_recruit(raceId) )
  430. button_recruit.enable();
  431. else
  432. button_recruit.disable();
  433. if( can_train(raceId) )
  434. button_train.enable();
  435. else
  436. button_train.disable();
  437. //------- detect buttons --------//
  438. if( button_recruit.detect() )
  439. recruit(-1, 0, COMMAND_PLAYER);
  440. if( button_train.detect() )
  441. {
  442. town_menu_mode = TOWN_MENU_TRAIN;
  443. disable_refresh = 1; // static var for disp_info() only
  444. info.disp();
  445. disable_refresh = 0;
  446. return;
  447. }
  448. int rc;
  449. if( (rc=button_tax.detect(0, 0, 1)) > 0 ) // 1-detect right-clicking
  450. {
  451. disp_auto_loyalty();
  452. // ##### begin Gilbert 26/9 ########//
  453. se_ctrl.immediate_sound("TURN_ON");
  454. // ##### end Gilbert 26/9 ########//
  455. if( rc==1 )
  456. {
  457. town_array[town_recno]->collect_tax(COMMAND_PLAYER);
  458. }
  459. else if( rc==2 ) // right click
  460. {
  461. town_menu_mode = TOWN_MENU_SET_AUTO_COLLECT_TAX;
  462. disable_refresh = 1; // static var for disp_info() only
  463. info.disp();
  464. disable_refresh = 0;
  465. }
  466. }
  467. if( (rc=button_grant.detect(0, 0, 1)) > 0 )
  468. {
  469. disp_auto_loyalty();
  470. // ##### begin Gilbert 26/9 ########//
  471. se_ctrl.immediate_sound("TURN_ON");
  472. // ##### end Gilbert 26/9 ########//
  473. if( rc==1 )
  474. {
  475. town_array[town_recno]->reward(COMMAND_PLAYER);
  476. }
  477. else if( rc==2 ) // right click
  478. {
  479. town_menu_mode = TOWN_MENU_SET_AUTO_GRANT;
  480. disable_refresh = 1; // static var for disp_info() only
  481. info.disp();
  482. disable_refresh = 0;
  483. }
  484. }
  485. if(train_unit_recno)
  486. {
  487. if((rc = button_cancel_training.detect()))
  488. {
  489. if( !remote.is_enable() )
  490. {
  491. cancel_train_unit();
  492. info.disp();
  493. }
  494. else
  495. {
  496. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_SKIP_RECRUIT, sizeof(short));
  497. shortPtr[0] = town_recno;
  498. }
  499. }
  500. }
  501. }
  502. //----------- End of function Town::detect_main_menu -----------//
  503. //--------- Begin of function Town::disp_basic_info ---------//
  504. //
  505. void Town::disp_basic_info(int refreshFlag)
  506. {
  507. if( refreshFlag == INFO_REPAINT )
  508. {
  509. vga.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+21 );
  510. if( nation_recno )
  511. {
  512. font_san.center_put( INFO_X1+21, INFO_Y1, INFO_X2-2, INFO_Y1+21, town_name() );
  513. char *nationPict = image_button.get_ptr("V_COLCOD");
  514. vga_front.put_bitmap_trans_remap_decompress(INFO_X1+3, INFO_Y1+2, nationPict, game.get_color_remap_table(nation_recno, 0) );
  515. }
  516. else
  517. {
  518. font_san.center_put( INFO_X1, INFO_Y1, INFO_X2-2, INFO_Y1+21, town_name() );
  519. }
  520. }
  521. }
  522. //----------- End of function Town::disp_basic_info -----------//
  523. //--------- Begin of function Town::disp_train_info ---------//
  524. //
  525. void Town::disp_train_info(int refreshFlag)
  526. {
  527. if( !train_unit_recno || nation_recno!=nation_array.player_recno )
  528. return;
  529. int dispY1 = INFO_Y1+26;
  530. Unit* unitPtr = unit_array[train_unit_recno];
  531. int x=MSG_X1+4, y=MSG_Y1+4;
  532. if( refreshFlag == INFO_REPAINT )
  533. {
  534. vga.d3_panel_up( MSG_X1, MSG_Y1, MSG_X2, MSG_Y2 );
  535. vga.d3_panel_down(x, y, x+RACE_ICON_WIDTH+3, y+RACE_ICON_HEIGHT+3 );
  536. vga_front.put_bitmap(x+2, y+2, race_res[unitPtr->race_id]->icon_bitmap_ptr );
  537. // vga.d3_panel_down(x+RACE_ICON_WIDTH+6, y, MSG_X2-4, MSG_Y2-4 );
  538. }
  539. int totalDays;
  540. if( config.fast_build && nation_recno==nation_array.player_recno )
  541. totalDays = TOTAL_TRAIN_DAYS/2;
  542. else
  543. totalDays = TOTAL_TRAIN_DAYS;
  544. vga_front.indicator( 0, x+RACE_ICON_WIDTH+6, y, float(sys.frame_count-start_train_frame_no),
  545. float(totalDays * FRAMES_PER_DAY), VGA_GRAY );
  546. button_cancel_training.paint(MSG_X2-27, MSG_Y1+2, "V_X-U", "V_X-D");
  547. button_cancel_training.set_help_code( "CANCELTRA" );
  548. }
  549. //----------- End of function Town::disp_train_info -----------//
  550. //------ Begin of function Town::browse_selected_race_id ------//
  551. //
  552. // Return the id. of the race selected in the town's race browser.
  553. //
  554. int Town::browse_selected_race_id()
  555. {
  556. err_when( town_recno != town_array.selected_recno ); // the current town must be the selected one when this function is called
  557. if( browse_race_town_recno != town_recno ) // the browser still hasn't displayed this town yet. This happens when the selected town is just changed, and this function is called before the town interface is refreshed
  558. return 0;
  559. if( browse_race.none_record )
  560. return 0;
  561. int raceCount = race_filter();
  562. if( raceCount != browse_race.total_rec() ||
  563. raceCount != recruit_race_count )
  564. {
  565. info.disp();
  566. }
  567. err_when( browse_race.recno() < 1 );
  568. err_when( browse_race.recno() > raceCount );
  569. err_when( browse_race.recno() > browse_race.total_rec() );
  570. return race_filter(browse_race.recno());
  571. }
  572. //------ End of function Town::browse_selected_race_id ------//
  573. //--------- Begin of function race_filter ---------//
  574. //
  575. // Filter those races that are in the town and can be trained.
  576. //
  577. static int race_filter(int recNo)
  578. {
  579. err_when( recNo && recNo < 1 );
  580. err_when( recNo && recNo > recruit_race_count );
  581. err_when( recNo && recNo > browse_race.total_rec() );
  582. int i, recCount=0;
  583. Town* townPtr = town_array[Town::if_town_recno];
  584. for( i=0 ; i<MAX_RACE ; i++ )
  585. {
  586. if( townPtr->race_pop_array[i] > 0 )
  587. recCount++;
  588. if( recNo && recCount==recNo )
  589. return i+1;
  590. }
  591. err_when( recNo );
  592. return recCount;
  593. }
  594. //----------- End of function race_filter -----------//
  595. //-------- Begin of static function put_race_rec --------//
  596. //
  597. static void put_race_rec(int recNo, int x, int y, int refreshFlag)
  598. {
  599. //-------- display race icon -------//
  600. int raceId = race_filter(recNo);
  601. RaceInfo* raceInfo = race_res[raceId];
  602. if( refreshFlag == INFO_REPAINT )
  603. {
  604. vga.d3_panel_down(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
  605. vga_front.put_bitmap(x+3, y+3, raceInfo->icon_bitmap_ptr);
  606. }
  607. //--------- set help parameters --------//
  608. if( mouse.in_area(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4) )
  609. help.set_unit_help( raceInfo->basic_unit_id, 0, x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
  610. //-------- display race name --------//
  611. Town* townPtr = town_array[Town::if_town_recno];
  612. font_mid.put( x+46, y+6, townPtr->race_pop_array[raceId-1],1, x+87 );
  613. font_mid.put( x+88, y+6, townPtr->jobless_race_pop_array[raceId-1], 1, x+129 );
  614. //---- only display loyalty if this town is controlled by a nation ----//
  615. int curLoyalty, targetLoyalty;
  616. int x2 = x+browse_race.rec_width-1;
  617. if( townPtr->nation_recno )
  618. {
  619. curLoyalty = (int) townPtr->race_loyalty_array[raceId-1];
  620. targetLoyalty = (int) townPtr->race_target_loyalty_array[raceId-1];
  621. }
  622. else
  623. {
  624. curLoyalty = (int) townPtr->race_resistance_array[raceId-1][nation_array.player_recno-1];
  625. targetLoyalty = (int) townPtr->race_target_resistance_array[raceId-1][nation_array.player_recno-1];
  626. if( targetLoyalty > curLoyalty ) // resistance only decrease, won't increase
  627. targetLoyalty = -1; // don't display the decrease target
  628. }
  629. //---------- display loyalty/resistance ------------//
  630. int dispArrow=0;
  631. String str;
  632. if( curLoyalty == targetLoyalty || targetLoyalty == -1 ) // only display up and down arrow for independent town's resistance
  633. {
  634. str = curLoyalty;
  635. }
  636. else
  637. {
  638. str = curLoyalty;
  639. str += " ";
  640. str += targetLoyalty;
  641. dispArrow=1;
  642. }
  643. x2 = font_mid.center_put( x+110, y+6, x2, y+5+font_mid.height(), str, 1 );
  644. //--------- display up/down arrow -----------//
  645. if( dispArrow )
  646. {
  647. x = x2-font_mid.text_width( m.format(targetLoyalty) ) - 8;
  648. if( (int) targetLoyalty > (int) curLoyalty )
  649. image_icon.put_join( x+1, y+9, "ARROWUP" );
  650. else if( (int) targetLoyalty < (int) curLoyalty )
  651. image_icon.put_join( x+1, y+9, "ARROWDWN" );
  652. }
  653. }
  654. //----------- End of static function put_race_rec -----------//
  655. //--------- Begin of function Town::disp_train_menu ---------//
  656. //
  657. void Town::disp_train_menu(int refreshFlag)
  658. {
  659. // ####### begin Gilbert 13/9 ########//
  660. if( refreshFlag == INFO_UPDATE )
  661. {
  662. for( int i=1; i<=MAX_TRAINABLE_SKILL; i++)
  663. {
  664. button_skill[i-1].paint(-1,0);
  665. // button_queue_skill[i] is called by automatically
  666. }
  667. }
  668. else if( refreshFlag == INFO_REPAINT )
  669. {
  670. font_san.d3_put( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+18, "Train (Cost:$30, Skill:20)" );
  671. int x=INFO_X1, y=INFO_Y1+24;
  672. for(int i=1; i<=MAX_TRAINABLE_SKILL; i++)
  673. {
  674. //disp_train_button(y, i, 1);
  675. button_queue_skill[i-1].create(INFO_X1+COUNT_BUTTON_OFFSET_X,
  676. y+COUNT_BUTTON_OFFSET_Y,
  677. INFO_X1+COUNT_BUTTON_OFFSET_X+COUNT_BUTTON_WIDTH-1,
  678. y+COUNT_BUTTON_OFFSET_Y+COUNT_BUTTON_HEIGHT-1,
  679. i_disp_queue_skill_button, ButtonCustomPara(this,i));
  680. button_skill[i-1].paint(INFO_X1, y,
  681. INFO_X2, y+BUTTON_ACTION_HEIGHT-1,
  682. i_disp_skill_button, ButtonCustomPara(&button_queue_skill[i-1],i) );
  683. y += BUTTON_ACTION_HEIGHT;
  684. }
  685. button_cancel3.paint( INFO_X1, y, INFO_X2, y+BUTTON_ACTION_HEIGHT*3/4-1,
  686. ButtonCustom::disp_text_button_func, ButtonCustomPara((void*)"Done",0) );
  687. }
  688. // ####### end Gilbert 13/9 ########//
  689. }
  690. //----------- End of function Town::disp_train_menu -----------//
  691. // ######### begin Gilbert 13/9 #########//
  692. //-------- Begin of function i_disp_skill_button --------//
  693. //
  694. static void i_disp_skill_button(ButtonCustom *button, int repaintBody)
  695. {
  696. int x1 = button->x1;
  697. int y1 = button->y1;
  698. int x2 = button->x2;
  699. int y2 = button->y2;
  700. if( !button->pushed_flag )
  701. {
  702. if( repaintBody )
  703. {
  704. vga.blt_buf(x1, y1, x2, y2, 0);
  705. vga.d3_panel2_up( x1, y1, x2, y2, 1 );
  706. }
  707. x2--;
  708. y2--;
  709. }
  710. else
  711. {
  712. if( repaintBody )
  713. {
  714. vga.blt_buf(x1, y1, x2, y2, 0);
  715. vga.d3_panel2_down( x1, y1, x2, y2, 1 );
  716. }
  717. x1++;
  718. y1++;
  719. }
  720. ButtonCustom *queueButton = (ButtonCustom *)button->custom_para.ptr;
  721. if( repaintBody)
  722. {
  723. // display skill large icon
  724. short skillId = button->custom_para.value;
  725. char str[9] = "U_";
  726. strcat( str, Skill::skill_code_array[skillId-1] );
  727. char *bitmapPtr = image_button.get_ptr(str);
  728. vga_front.put_bitmap_trans_decompress(x1, y1+4, bitmapPtr);
  729. // put name
  730. if( skillId == SKILL_MFT )
  731. font_bible.put(x1+50, y1+11, "Manufacturing" ); // the string in skill_str_array[] is "Manufacture".
  732. else
  733. font_bible.put(x1+50, y1+11, Skill::skill_str_array[skillId-1]);
  734. }
  735. // display small button
  736. queueButton->paint(-1, repaintBody);
  737. }
  738. //--------- End of static function i_disp_skill_button ---------//
  739. /*
  740. //--------- Begin of function Town::disp_queue_button ---------//
  741. void Town::disp_queue_button(int y, int skillId, int buttonUp)
  742. {
  743. //----- count the no. of units queued for this ship ------//
  744. int x=INFO_X1+2+COUNT_BUTTON_OFFSET_X;
  745. int trainCount=0;
  746. for(int i=0; i<train_queue_count; i++)
  747. {
  748. if(train_queue_skill_array[i] == skillId)
  749. trainCount++;
  750. }
  751. if(train_unit_recno)
  752. {
  753. Unit *unitPtr = unit_array[train_unit_recno];
  754. if(unitPtr->skill.skill_id==skillId)
  755. trainCount++;
  756. }
  757. if(buttonUp)
  758. vga.d3_panel_up(x, y, x+COUNT_BUTTON_WIDTH-1, y+COUNT_BUTTON_HEIGHT-1);
  759. else
  760. {
  761. vga.d3_panel_down(x, y, x+COUNT_BUTTON_WIDTH-1, y+COUNT_BUTTON_HEIGHT-1);
  762. x++;
  763. y++;
  764. }
  765. font_san.center_put(x, y, x+COUNT_BUTTON_WIDTH-1 , y+COUNT_BUTTON_HEIGHT-1, m.format(trainCount));
  766. }
  767. //----------- End of function Town::disp_queue_button -----------//
  768. */
  769. //-------- Begin of static function i_disp_queue_skill_button --------//
  770. //
  771. static void i_disp_queue_skill_button(ButtonCustom *button, int repaintBody)
  772. {
  773. Town *townPtr= (Town *)button->custom_para.ptr;
  774. int x1 = button->x1;
  775. int y1 = button->y1;
  776. int x2 = button->x2;
  777. int y2 = button->y2;
  778. if( !button->pushed_flag )
  779. {
  780. if( repaintBody )
  781. {
  782. vga.blt_buf(x1, y1, x2, y2, 0);
  783. vga.d3_panel2_up( x1, y1, x2, y2, 1, 1);
  784. }
  785. x2--;
  786. y2--;
  787. }
  788. else
  789. {
  790. if( repaintBody )
  791. {
  792. vga.blt_buf(x1, y1, x2, y2, 0);
  793. vga.d3_panel2_down( x1, y1, x2, y2, 1, 1);
  794. }
  795. x1++;
  796. y1++;
  797. }
  798. //----- count the no. of units queued for this skill ------//
  799. short skillId = button->custom_para.value;
  800. int queuedCount=0;
  801. for( int i=0 ; i<townPtr->train_queue_count ; i++ )
  802. {
  803. if( townPtr->train_queue_skill_array[i] == skillId )
  804. queuedCount++;
  805. }
  806. if(townPtr->train_unit_recno)
  807. {
  808. Unit *unitPtr = unit_array[townPtr->train_unit_recno];
  809. // ##### begin Gilbert 10/10 #######//
  810. if(unitPtr->skill.skill_id==skillId
  811. //### begin alex 17/3 ###//
  812. //|| (unitPtr->spy_recno && skillId == SKILL_SPYING) )
  813. || (skillId == SKILL_SPYING && unitPtr->spy_recno && unitPtr->skill.skill_id == 0) ) // 0 for spying-training
  814. //#### end alex 17/3 ####//
  815. queuedCount++;
  816. // ##### end Gilbert 10/10 #######//
  817. }
  818. font_mid.center_put( x1+3, y1+3, x2-3, y2-3, m.format(queuedCount), 1);
  819. }
  820. //--------- End of static function i_disp_queue_skill_button ---------//
  821. // ######### end Gilbert 13/9 #########//
  822. //--------- Begin of function Town::detect_train_menu ---------//
  823. //
  824. void Town::detect_train_menu()
  825. {
  826. int x=INFO_X1+2, y=INFO_Y1+24, rc, quitFlag;
  827. for(int b=1; b<=MAX_TRAINABLE_SKILL; ++b)
  828. {
  829. // ###### begin Gilbert 10/9 ########//
  830. //------ detect pressing on the small queue count button -------//
  831. rc = 0;
  832. if( (rc = button_queue_skill[b-1].detect(0,0,2)) != 0)
  833. {
  834. quitFlag = 0; // don't quit the menu right after pressing the button
  835. }
  836. //------ detect pressing on the big button -------//
  837. else if( (rc= button_skill[b-1].detect(0,0,2)) != 0)
  838. {
  839. quitFlag = 1; // quit the menu right after pressing the button
  840. }
  841. // ###### end Gilbert 10/9 ########//
  842. //------- process the action --------//
  843. if( rc > 0 )
  844. {
  845. if( rc==1 ) // left button
  846. {
  847. if( remote.is_enable() )
  848. {
  849. // packet structure : <town recno> <skill id> <race id>
  850. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 3*sizeof(short) );
  851. shortPtr[0] = town_recno;
  852. shortPtr[1] = b;
  853. shortPtr[2] = race_filter(browse_race.recno());
  854. }
  855. else
  856. add_queue(b, race_filter(browse_race.recno()) );
  857. // ##### begin Gilbert 26/9 ########//
  858. se_ctrl.immediate_sound("TURN_ON");
  859. // ##### end Gilbert 26/9 ########//
  860. }
  861. else // right button - remove queue
  862. {
  863. if( remote.is_enable() )
  864. {
  865. // packet structure : <town recno> <skill id> <race id>
  866. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 3*sizeof(short) );
  867. shortPtr[0] = town_recno;
  868. shortPtr[1] = b;
  869. shortPtr[2] = -1; // -1 race_id represent remove queue
  870. }
  871. else
  872. remove_queue(b);
  873. // ##### begin Gilbert 26/9 ########//
  874. se_ctrl.immediate_sound("TURN_OFF");
  875. // ##### end Gilbert 26/9 ########//
  876. }
  877. if( quitFlag )
  878. info.disp(); // info.disp() will call put_info() which will switch mode back to the main menu mode
  879. // ####### begin Gilbert 10/9 ######//
  880. else
  881. // disp_queue_button(y+COUNT_BUTTON_OFFSET_Y, b, 1);
  882. info.update();
  883. // ####### end Gilbert 10/9 ######//
  884. return;
  885. }
  886. y += BUTTON_ACTION_HEIGHT;
  887. }
  888. //------ detect the cancel button --------//
  889. if( button_cancel3.detect() || mouse.any_click(1) ) // press the cancel button or right click
  890. {
  891. // ##### begin Gilbert 26/9 ########//
  892. se_ctrl.immediate_sound("TURN_OFF");
  893. // ##### end Gilbert 26/9 ########//
  894. town_menu_mode = TOWN_MENU_MAIN;
  895. info.disp();
  896. }
  897. }
  898. //----------- End of function Town::detect_train_menu -----------//
  899. //--------- Begin of function Town::disp_auto_menu ---------//
  900. //
  901. void Town::disp_auto_menu(int modeCollectTax)
  902. {
  903. int curAutoLoyalty;
  904. Nation* nationPtr = nation_array[nation_recno];
  905. if( modeCollectTax )
  906. curAutoLoyalty = auto_collect_tax_loyalty;
  907. else
  908. curAutoLoyalty = auto_grant_loyalty;
  909. //---------- paint buttons ------------//
  910. char* headingStr;
  911. if( modeCollectTax )
  912. headingStr = "Automatically Collect Tax from Villagers when their Loyalty reaches:";
  913. else
  914. headingStr = "Automatically Grant Money to Villagers when their Loyalty drops below:";
  915. char* clickStr = "(Left-click below to apply to this village. Right-click below to apply to all your villages.)";
  916. vga.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+110 );
  917. font_san.put_paragraph( INFO_X1+7, INFO_Y1+8, INFO_X2-7, INFO_Y2-5, headingStr );
  918. font_san.put_paragraph( INFO_X1+7, INFO_Y1+58, INFO_X2-7, INFO_Y2-5, clickStr );
  919. int i, loyaltyLevel, y=INFO_Y1+114;
  920. for( i=0, loyaltyLevel=30 ; i<BUTTON_LOYALTY_COUNT ; loyaltyLevel+=10, i++, y+=20 )
  921. button_loyalty_array[i].paint_text( INFO_X1, y, INFO_X2, y+18, m.format(loyaltyLevel), 0, loyaltyLevel==curAutoLoyalty );
  922. button_loyalty_disabled.paint_text( INFO_X1, y, INFO_X2, y+18, "Disabled", 0, curAutoLoyalty==0 );
  923. y+=20;
  924. button_cancel2.paint_text( INFO_X1, y, INFO_X2, y+18, "Cancel" );
  925. }
  926. //----------- End of function Town::disp_auto_menu -----------//
  927. //--------- Begin of function Town::detect_auto_menu ---------//
  928. //
  929. void Town::detect_auto_menu(int modeCollectTax)
  930. {
  931. int i, rc=0, loyaltyLevel;
  932. for( i=0, loyaltyLevel=30 ; i<BUTTON_LOYALTY_COUNT ; loyaltyLevel+=10, i++ )
  933. {
  934. rc = button_loyalty_array[i].detect(0, 0, 1);
  935. if( rc )
  936. break;
  937. }
  938. if( !rc )
  939. {
  940. rc = button_loyalty_disabled.detect(0, 0, 1);
  941. loyaltyLevel = 0;
  942. }
  943. //------ set new settings now -------//
  944. if( rc==1 )
  945. {
  946. if( modeCollectTax )
  947. {
  948. if( !remote.is_enable() )
  949. {
  950. set_auto_collect_tax_loyalty(loyaltyLevel);
  951. }
  952. else
  953. {
  954. // packet structure <town recno> <loyalty level>
  955. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_TAX, 2*sizeof(short) );
  956. *shortPtr = town_recno;
  957. shortPtr[1] = loyaltyLevel;
  958. }
  959. }
  960. else
  961. {
  962. if( !remote.is_enable() )
  963. {
  964. set_auto_grant_loyalty(loyaltyLevel);
  965. }
  966. else
  967. {
  968. // packet structure <town recno> <loyalty level>
  969. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_GRANT, 2*sizeof(short) );
  970. *shortPtr = town_recno;
  971. shortPtr[1] = loyaltyLevel;
  972. }
  973. }
  974. }
  975. else if( rc==2 )
  976. {
  977. // ####### begin Gilbert 11/9 ########//
  978. //----- set the national policy -----//
  979. if( !remote.is_enable() )
  980. {
  981. Nation* nationPtr = nation_array[nation_recno];
  982. if( modeCollectTax )
  983. nationPtr->set_auto_collect_tax_loyalty(loyaltyLevel);
  984. else
  985. nationPtr->set_auto_grant_loyalty(loyaltyLevel);
  986. //----- update individual towns -----//
  987. Town* townPtr;
  988. for( i=town_array.size() ; i>0 ; i-- )
  989. {
  990. if( town_array.is_deleted(i) )
  991. continue;
  992. townPtr = town_array[i];
  993. if( townPtr->nation_recno == nation_recno )
  994. {
  995. if( modeCollectTax )
  996. townPtr->set_auto_collect_tax_loyalty(loyaltyLevel);
  997. else
  998. townPtr->set_auto_grant_loyalty(loyaltyLevel);
  999. }
  1000. }
  1001. }
  1002. else
  1003. {
  1004. err_when(!nation_recno);
  1005. if( modeCollectTax )
  1006. {
  1007. // packet structure <-nation recno> <loyalty level>
  1008. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_TAX, 2*sizeof(short) );
  1009. *shortPtr = -nation_recno;
  1010. shortPtr[1] = loyaltyLevel;
  1011. }
  1012. else
  1013. {
  1014. // packet structure <-nation recno> <loyalty level>
  1015. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_GRANT, 2*sizeof(short) );
  1016. *shortPtr = -nation_recno;
  1017. shortPtr[1] = loyaltyLevel;
  1018. }
  1019. }
  1020. // ####### end Gilbert 11/9 ########//
  1021. }
  1022. //--------------------------------------//
  1023. if( button_cancel2.detect() || rc )
  1024. {
  1025. // ##### begin Gilbert 26/9 ########//
  1026. se_ctrl.immediate_sound("TURN_OFF");
  1027. // ##### begin Gilbert 26/9 ########//
  1028. town_menu_mode = TOWN_MENU_MAIN;
  1029. info.disp();
  1030. }
  1031. }
  1032. //----------- End of function Town::detect_auto_menu -----------//
  1033. //--------- Begin of function Town::disp_spy_menu ---------//
  1034. //
  1035. void Town::disp_spy_menu(int refreshFlag)
  1036. {
  1037. disp_basic_info(refreshFlag);
  1038. //---------- paint controls -----------//
  1039. if( refreshFlag == INFO_REPAINT )
  1040. {
  1041. spy_count = spy_filter();
  1042. //------ display browser field description -------//
  1043. int x=RACE_BROWSE_X1+2;
  1044. int y=RACE_BROWSE_Y1-23;
  1045. vga.d3_panel_up( RACE_BROWSE_X1, y, RACE_BROWSE_X2, RACE_BROWSE_Y1-3 );
  1046. font_san.put( x+4 , y+4, "Spy Skill" );
  1047. font_san.put( x+70 , y+4, "Loyalty" );
  1048. font_san.put( x+130, y+4, "Action" );
  1049. //------------ create browser ------------//
  1050. browse_spy.init( RACE_BROWSE_X1, RACE_BROWSE_Y1, RACE_BROWSE_X2, RACE_BROWSE_Y2,
  1051. 0, 25, spy_count, put_spy_rec );
  1052. browse_spy.open(1);
  1053. }
  1054. else
  1055. {
  1056. //---------- update controls -----------//
  1057. if( spy_count != spy_filter() )
  1058. {
  1059. spy_count = spy_filter();
  1060. if( spy_count>0 )
  1061. {
  1062. disable_refresh = 1; // stay in the spy menu mode if disable_refresh is 1
  1063. info.disp();
  1064. disable_refresh = 0;
  1065. }
  1066. else
  1067. info.disp(); // reset to the main menu mode if disable_refresh is 0
  1068. return;
  1069. }
  1070. else
  1071. browse_spy.update();
  1072. }
  1073. //----------- create the paint button ----------//
  1074. if( refreshFlag == INFO_REPAINT )
  1075. {
  1076. int x=BUTTON_X1, y=RACE_BROWSE_Y2+5;
  1077. button_spy_mobilize.paint( x, y, 'A', "MOBILSPY" );
  1078. x+=BUTTON_ACTION_WIDTH;
  1079. //--------- reward spy button --------//
  1080. button_spy_reward.paint( x, y, 'A', "REWARD" );
  1081. x+=BUTTON_ACTION_WIDTH;
  1082. if( nation_recno != nation_array.player_recno ) // if the spy is in another nation's town
  1083. {
  1084. button_spy_action.paint( x, y, 'A', "SPYCHACT" );
  1085. x+=BUTTON_ACTION_WIDTH;
  1086. }
  1087. if( nation_recno && nation_recno != nation_array.player_recno )
  1088. {
  1089. button_spy_view_secret.paint( x, y, 'A', "VSECRET" );
  1090. x+=BUTTON_ACTION_WIDTH;
  1091. if( x+BUTTON_ACTION_WIDTH-5 > INFO_X2 )
  1092. {
  1093. x = BUTTON_X1;
  1094. y += BUTTON_ACTION_HEIGHT;
  1095. }
  1096. }
  1097. button_cancel.paint( x, y, 'A', "PREVMENU" );
  1098. }
  1099. }
  1100. //----------- End of function Town::disp_spy_menu -----------//
  1101. //--------- Begin of function Town::detect_spy_menu ---------//
  1102. //
  1103. void Town::detect_spy_menu()
  1104. {
  1105. browse_spy.detect();
  1106. Spy* spyPtr = spy_array[ spy_filter( browse_spy.recno() ) ];
  1107. //------- mobilize spy --------//
  1108. if( button_spy_mobilize.detect() )
  1109. {
  1110. if( !remote.is_enable() )
  1111. {
  1112. if( spyPtr->mobilize_town_spy() )
  1113. {
  1114. spyPtr->notify_cloaked_nation_flag = 0; // reset it so the player can control it
  1115. disp_spy_menu( INFO_UPDATE );
  1116. }
  1117. }
  1118. else
  1119. {
  1120. // packet structure <spy recno>
  1121. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_SPY_LEAVE_TOWN, sizeof(short) );
  1122. *shortPtr = spyPtr->spy_recno;
  1123. }
  1124. }
  1125. //------ reward spy ---------//
  1126. else if( button_spy_reward.detect() )
  1127. {
  1128. spyPtr->reward(COMMAND_PLAYER);
  1129. }
  1130. //----- change spy action --------//
  1131. if( nation_recno != nation_array.player_recno ) // if the spy is in another nation's town
  1132. {
  1133. if( button_spy_action.detect() ) // set action mode
  1134. {
  1135. if( !remote.is_enable() )
  1136. {
  1137. spyPtr->set_next_action_mode();
  1138. disp_spy_menu( INFO_UPDATE );
  1139. }
  1140. else
  1141. {
  1142. // packet structure <spy recno>
  1143. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_SPY_CYCLE_ACTION, sizeof(short) );
  1144. *shortPtr = spyPtr->spy_recno;
  1145. }
  1146. }
  1147. }
  1148. //----- view secret report ------/
  1149. if( nation_recno && nation_recno != nation_array.player_recno )
  1150. {
  1151. if( button_spy_view_secret.detect() )
  1152. {
  1153. action_spy_recno = spyPtr->spy_recno;
  1154. town_menu_mode = TOWN_MENU_VIEW_SECRET;
  1155. disable_refresh = 1;
  1156. info.disp();
  1157. disable_refresh = 0;
  1158. }
  1159. }
  1160. //--------- cancel -----------//
  1161. if( button_cancel.detect() || mouse.any_click(1) ) // right click to cancel
  1162. info.disp();
  1163. }
  1164. //----------- End of function Town::detect_spy_menu -----------//
  1165. //--------- Begin of function Town::has_player_spy ---------//
  1166. //
  1167. // Whether this town has any player spies.
  1168. //
  1169. int Town::has_player_spy()
  1170. {
  1171. int i;
  1172. for( i=0 ; i<MAX_RACE ; i++ )
  1173. {
  1174. if( race_spy_count_array[i] > 0 )
  1175. break;
  1176. }
  1177. if( i==MAX_RACE ) // no spies in this nation
  1178. return 0;
  1179. //----- look for player spy in the spy_array -----//
  1180. Spy* spyPtr;
  1181. for( i=spy_array.size() ; i>=1 ; i-- )
  1182. {
  1183. if( spy_array.is_deleted(i) )
  1184. continue;
  1185. spyPtr = spy_array[i];
  1186. if( spyPtr->spy_place==SPY_TOWN &&
  1187. spyPtr->spy_place_para==town_recno &&
  1188. spyPtr->true_nation_recno==nation_array.player_recno )
  1189. {
  1190. return 1;
  1191. }
  1192. }
  1193. return 0;
  1194. }
  1195. //----------- End of function Town::has_player_spy -----------//
  1196. //--------- Begin of function spy_filter ---------//
  1197. //
  1198. static int spy_filter(int recNo)
  1199. {
  1200. Spy* spyPtr;
  1201. int recCount=0;
  1202. for( int i=spy_array.size() ; i>=1 ; i-- )
  1203. {
  1204. if( spy_array.is_deleted(i) )
  1205. continue;
  1206. spyPtr = spy_array[i];
  1207. if( spyPtr->spy_place==SPY_TOWN &&
  1208. spyPtr->spy_place_para==Town::if_town_recno &&
  1209. spyPtr->true_nation_recno==nation_array.player_recno )
  1210. {
  1211. recCount++;
  1212. }
  1213. if( recNo && recCount==recNo )
  1214. return i;
  1215. }
  1216. err_when( recNo );
  1217. return recCount;
  1218. }
  1219. //----------- End of function spy_filter -----------//
  1220. //-------- Begin of static function put_spy_rec --------//
  1221. //
  1222. static void put_spy_rec(int recNo, int x, int y, int refreshFlag)
  1223. {
  1224. int x2 = x+browse_spy.rec_width-1;
  1225. //-------- display icon of the spy unit -----//
  1226. Spy* spyPtr = spy_array[ spy_filter(recNo) ];
  1227. if( refreshFlag == INFO_REPAINT )
  1228. {
  1229. vga.d3_panel_down(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
  1230. vga_front.put_bitmap(x+3, y+3, race_res[spyPtr->race_id]->icon_bitmap_ptr);
  1231. }
  1232. //--------- set help parameters --------//
  1233. if( mouse.in_area(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4) )
  1234. {
  1235. int unitId = race_res[spyPtr->race_id]->basic_unit_id;
  1236. help.set_unit_help( unitId, 0, x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
  1237. }
  1238. //-------- display spy skill -------//
  1239. font_san.put( x+40, y+6, spyPtr->spy_skill, 1, x+66 );
  1240. //-------- display spy loyalty -------//
  1241. font_san.put( x+67, y+6, spyPtr->spy_loyalty, 1, x+94 );
  1242. //------ display the action mode of the spy ------//
  1243. vga.blt_buf( x+95, y+6, x2, y+5+font_san.height(), 0 );
  1244. font_san.center_put( x+95, y+6, x2, y+5+font_san.height(), spyPtr->action_str() );
  1245. }
  1246. //----------- End of static function put_spy_rec -----------//
  1247. //--------- Begin of function Town::recruit ---------//
  1248. //
  1249. // <int> trainSkillId = -1 - non-trained unit
  1250. // >=1 - skill id. of the unit to be trained.
  1251. //
  1252. // [int] raceId = the race id. of the unit to be recruited
  1253. // (default: the currently selected race)
  1254. //
  1255. // return: <int> recno of the recruited unit
  1256. //
  1257. int Town::recruit(int trainSkillId, int raceId, char remoteAction)
  1258. {
  1259. //---- we can't train a new one when there is one currently under training ---//
  1260. if( trainSkillId >= 1 && train_unit_recno )
  1261. return 0;
  1262. //--------------------------------------------//
  1263. if( !raceId )
  1264. {
  1265. if( browse_race.recno() > race_filter() )
  1266. return 0;
  1267. raceId = race_filter(browse_race.recno());
  1268. }
  1269. if( !remoteAction && remote.is_enable() )
  1270. {
  1271. // packet structure : <town recno> <skill id> <race id>
  1272. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 3*sizeof(short));
  1273. shortPtr[0] = town_recno;
  1274. shortPtr[1] = trainSkillId;
  1275. shortPtr[2] = raceId;
  1276. return 0;
  1277. }
  1278. //---- check if there are units of the race ready for training ----//
  1279. int recruitableCount = recruitable_race_pop(raceId, 1);
  1280. if( recruitableCount == 0 )
  1281. return 0;
  1282. err_when( recruitableCount < 0 ); // 1-allow recruiting spies
  1283. //-------- create an unit ------//
  1284. int townRecno = town_recno;
  1285. int nationRecno = nation_recno; // save this town's info that is needed as promote_pop() will delete Town if all population of the town are promoted
  1286. //--- if there are spies in this town, chances are that they will be mobilized ---//
  1287. int shouldTrainSpy = race_spy_count_array[raceId-1] >= m.random(recruitableCount)+1; // 1-allow recruiting spies
  1288. //---- if we are trying to train an enemy to our spy, then... -----//
  1289. if( shouldTrainSpy && trainSkillId == SKILL_SPYING )
  1290. {
  1291. //-- if there are other non-spy units in the town, then train the other and don't train the spy --//
  1292. if( recruitableCount > race_spy_count_array[raceId-1] )
  1293. {
  1294. shouldTrainSpy = 0;
  1295. }
  1296. //--- if all remaining units are spies, when you try to train one, all of them will become mobilized ---//
  1297. else
  1298. {
  1299. int spyRecno = spy_array.find_town_spy(town_recno, raceId, 1);
  1300. err_when( !spyRecno );
  1301. Spy* spyPtr = spy_array[spyRecno];
  1302. if( !spyPtr->mobilize_town_spy() )
  1303. return 0;
  1304. spyPtr->change_cloaked_nation( spyPtr->true_nation_recno );
  1305. return 0;
  1306. }
  1307. }
  1308. //------- if we should train a spy --------//
  1309. int unitRecno=0;
  1310. if( shouldTrainSpy )
  1311. {
  1312. int spyCount = spy_array.size();
  1313. int spyRecno = m.random(spyCount)+1;
  1314. Spy* spyPtr;
  1315. //-----------------------------------------------------//
  1316. // Spies from other nations will first be mobilized,
  1317. // when all peasants and spies are mobilized and
  1318. // the only ones left in the town are spies from our
  1319. // nation, then mobilize them finally.
  1320. //-----------------------------------------------------//
  1321. for( int mobileNationType=1 ; unitRecno==0 && mobileNationType<=2 ; mobileNationType++ )
  1322. {
  1323. if( mobileNationType==2 ) // only mobilize our own spies are there are the only ones in the town
  1324. {
  1325. if( recruitable_race_pop(raceId,1) > race_spy_count_array[raceId-1] ) // 1-allow recruiting spies
  1326. break;
  1327. }
  1328. for( int i=0 ; i<spyCount ; i++ )
  1329. {
  1330. if( ++spyRecno > spyCount )
  1331. spyRecno = 1;
  1332. if( spy_array.is_deleted(spyRecno) )
  1333. continue;
  1334. spyPtr = spy_array[spyRecno];
  1335. if( spyPtr->spy_place == SPY_TOWN
  1336. && spyPtr->spy_place_para == town_recno
  1337. // ##### patch begin Gilbert 9/4 ######//
  1338. && spyPtr->race_id == raceId
  1339. // ##### patch end Gilbert 9/4 ######//
  1340. )
  1341. {
  1342. if( mobileNationType==1 ) // only mobilize spies from other nations, don't mobilize spies of our own nation
  1343. {
  1344. if( spyPtr->true_nation_recno == nation_recno )
  1345. continue;
  1346. }
  1347. unitRecno = spyPtr->mobilize_town_spy(trainSkillId== -1); // the parameter is whether decreasing the population immediately, if decrease immediately in recruit mode, not in training mode, 1-mobilize spies
  1348. break;
  1349. }
  1350. }
  1351. }
  1352. }
  1353. //-------- mobilize normal peasant units -------//
  1354. if( !unitRecno )
  1355. unitRecno = mobilize_town_people(raceId, trainSkillId== -1, 0 ); // the 2nd parameter is whether decreasing the population immediately, if decrease immediately in recruit mode, not in training mode, 2nd para 0-don't mobilize spies
  1356. if( !unitRecno )
  1357. return 0;
  1358. err_when(unitRecno<=0 || unit_array.is_deleted(unitRecno));
  1359. if( !unitRecno )
  1360. return 0;
  1361. Unit* unitPtr = unit_array[unitRecno];
  1362. //-------- training skill -----------//
  1363. if( trainSkillId > 0 )
  1364. {
  1365. if( trainSkillId == SKILL_SPYING )
  1366. {
  1367. unitPtr->spy_recno = spy_array.add_spy(unitRecno, TRAIN_SKILL_LEVEL);
  1368. }
  1369. else
  1370. {
  1371. if( trainSkillId == SKILL_LEADING ) // also increase the combat level for leadership skill training
  1372. unitPtr->set_combat_level(TRAIN_SKILL_LEVEL);
  1373. unitPtr->skill.skill_id = trainSkillId;
  1374. unitPtr->skill.skill_level = TRAIN_SKILL_LEVEL;
  1375. }
  1376. nation_array[nationRecno]->add_expense( EXPENSE_TRAIN_UNIT, (float) TRAIN_SKILL_COST );
  1377. }
  1378. else
  1379. {
  1380. //------ recruitment without training decreases loyalty --------//
  1381. recruit_dec_loyalty(raceId);
  1382. if( unitPtr->is_own() )
  1383. {
  1384. se_res.far_sound(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), 1,
  1385. 'S', unitPtr->sprite_id, "RDY" );
  1386. }
  1387. }
  1388. //---- training solider or skilled unit takes time ----//
  1389. if( trainSkillId >= 0 )
  1390. {
  1391. err_when(unitRecno<=0 || unit_array.is_deleted(unitRecno));
  1392. err_when( train_unit_recno ); // if there is already a unit under training
  1393. train_unit_recno = unitRecno;
  1394. start_train_frame_no = sys.frame_count; // as an offset for displaying the progress bar correctly
  1395. unitPtr->deinit_sprite();
  1396. unitPtr->unit_mode = UNIT_MODE_UNDER_TRAINING;
  1397. unitPtr->unit_mode_para = town_recno;
  1398. }
  1399. //--- mobilize_pop() will delete the current Town if population goes down to 0 ---//
  1400. if( town_recno == town_array.selected_recno )
  1401. {
  1402. if( town_array.is_deleted(townRecno) )
  1403. info.disp();
  1404. }
  1405. return unitRecno;
  1406. }
  1407. //----------- End of function Town::recruit -----------//
  1408. //--------- Begin of function Town::recruit_dec_loyalty ---------//
  1409. //
  1410. // Decrease loyalty when an unit is recruited.
  1411. // This function is called by recruit() and Firm::pull_town_people()
  1412. //
  1413. // <int> raceId - the race to be recruited
  1414. // <int> decNow - decrease now, if it is 0, just return the
  1415. // loyalty to be decreased without actual decreasing.
  1416. // (default: 1)
  1417. //
  1418. // return: <int> - the loyalty decreased or to be decreased.
  1419. //
  1420. int Town::recruit_dec_loyalty(int raceId, int decNow)
  1421. {
  1422. float loyaltyDec = min( 5, (float) MAX_TOWN_POPULATION / race_pop_array[raceId-1] );
  1423. //------ recruitment without training decreases loyalty --------//
  1424. if( decNow )
  1425. {
  1426. loyaltyDec += accumulated_recruit_penalty/5;
  1427. loyaltyDec = min(loyaltyDec, 10);
  1428. accumulated_recruit_penalty += 5;
  1429. //-------------------------------------//
  1430. race_loyalty_array[raceId-1] -= loyaltyDec;
  1431. if( race_loyalty_array[raceId-1] < 0 )
  1432. race_loyalty_array[raceId-1] = (float) 0;
  1433. }
  1434. return (int) loyaltyDec;
  1435. }
  1436. //----------- End of function Town::recruit_dec_loyalty -----------//
  1437. //--------- Begin of function Town::process_train ---------//
  1438. void Town::process_train()
  1439. {
  1440. err_when( !train_unit_recno );
  1441. Unit* unitPtr = unit_array[train_unit_recno];
  1442. int raceId = unitPtr->race_id;
  1443. //---- if the unit being trained was killed -----//
  1444. int cancelFlag = 0;
  1445. err_when( jobless_race_pop_array[raceId-1] < 0 );
  1446. if( jobless_race_pop_array[raceId-1]==0 ) // the unit being trained was killed
  1447. {
  1448. cancelFlag = 1;
  1449. }
  1450. //-----------------------------------------------------------------//
  1451. //
  1452. // If after start training the unit (non-spy unit), a unit has been
  1453. // mobilized, resulting that the spy count >= jobless_race,
  1454. // we must cancel the training, otherwise when training finishes,
  1455. // and dec_pop is called, spy count will > jobless count and cause error.
  1456. //
  1457. //-----------------------------------------------------------------//
  1458. err_when( race_spy_count_array[raceId-1] > jobless_race_pop_array[raceId-1] );
  1459. if( race_spy_count_array[raceId-1] == jobless_race_pop_array[raceId-1] )
  1460. cancelFlag = 1;
  1461. if( cancelFlag )
  1462. {
  1463. unit_array.disappear_in_town(train_unit_recno, town_recno);
  1464. train_unit_recno = 0;
  1465. return;
  1466. }
  1467. //------------- process training ---------------//
  1468. int totalDays;
  1469. if( config.fast_build && nation_recno==nation_array.player_recno )
  1470. totalDays = TOTAL_TRAIN_DAYS/2;
  1471. else
  1472. totalDays = TOTAL_TRAIN_DAYS;
  1473. if( (int)(sys.frame_count-start_train_frame_no) / FRAMES_PER_DAY >= totalDays )
  1474. {
  1475. finish_train(unitPtr);
  1476. }
  1477. }
  1478. //----------- End of function Town::process_train -----------//
  1479. //--------- Begin of function Town::finish_train ---------//
  1480. void Town::finish_train(Unit* unitPtr)
  1481. {
  1482. err_when(train_unit_recno<=0 || unit_array.is_deleted(train_unit_recno));
  1483. SpriteInfo* spriteInfo = unitPtr->sprite_info;
  1484. int xLoc=loc_x1; // xLoc & yLoc are used for returning results
  1485. int yLoc=loc_y1;
  1486. if( !world.locate_space(xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height) )
  1487. return;
  1488. unitPtr->init_sprite(xLoc, yLoc);
  1489. if( unitPtr->is_own() )
  1490. se_res.far_sound( xLoc, yLoc, 1, 'S', unitPtr->sprite_id, "RDY");
  1491. unitPtr->unit_mode = 0; // reset it to 0 from UNIT_MODE_UNDER_TRAINING
  1492. train_unit_recno = 0;
  1493. int townRecno = town_recno; // save the recno as it can be deleted in dec_pop()
  1494. dec_pop(unitPtr->race_id, 0); // decrease the population now as the recruit() does do so
  1495. //---- if this trained unit is tied to an AI action ----//
  1496. if( train_unit_action_id )
  1497. {
  1498. nation_array[nation_recno]->process_action_id(train_unit_action_id);
  1499. train_unit_action_id = 0;
  1500. }
  1501. //----- refresh if this town is currently selected ------//
  1502. if(townRecno==town_array.selected_recno)
  1503. {
  1504. if(town_menu_mode==TOWN_MENU_MAIN)
  1505. {
  1506. info.disp();
  1507. }
  1508. else
  1509. {
  1510. disable_refresh = 1;
  1511. info.disp();
  1512. disable_refresh = 0;
  1513. }
  1514. }
  1515. }
  1516. //----------- End of function Town::finish_train -----------//
  1517. //--------- Begin of function Town::process_queue ---------//
  1518. void Town::process_queue()
  1519. {
  1520. if(train_queue_count==0)
  1521. return;
  1522. if(jobless_population==0)
  1523. return;
  1524. err_when(train_queue_count > MAX_TRAIN_QUEUE);
  1525. char queueCount = train_queue_count;
  1526. char skillId, raceId;
  1527. char i;
  1528. for(i=0; i<queueCount; ++i)
  1529. {
  1530. if(can_train(train_queue_race_array[i]))
  1531. {
  1532. skillId = train_queue_skill_array[i];
  1533. raceId = train_queue_race_array[i];
  1534. err_when(train_queue_count-i-1 < 0 || train_queue_count-i-1 > MAX_TRAIN_QUEUE);
  1535. memmove(train_queue_skill_array, train_queue_skill_array+i+1,
  1536. sizeof(train_queue_skill_array[0])*(train_queue_count-i-1));
  1537. memmove(train_queue_race_array, train_queue_race_array+i+1,
  1538. sizeof(train_queue_race_array[0])*(train_queue_count-i-1));
  1539. train_queue_count -= i+1;
  1540. recruit(skillId, raceId, COMMAND_AUTO);
  1541. break;
  1542. }
  1543. }
  1544. if(i==queueCount)
  1545. train_queue_count = 0;
  1546. if(town_menu_mode==TOWN_MENU_MAIN)
  1547. info.disp();
  1548. }
  1549. //----------- End of function Town::process_queue -----------//
  1550. //--------- Begin of function Town::add_queue ---------//
  1551. void Town::add_queue(char skillId, char raceId)
  1552. {
  1553. if(train_queue_count+(train_unit_recno>0)==MAX_TRAIN_QUEUE)
  1554. return;
  1555. train_queue_skill_array[train_queue_count] = skillId;
  1556. train_queue_race_array[train_queue_count++] = raceId;
  1557. if( !train_unit_recno )
  1558. process_queue();
  1559. }
  1560. //----------- End of function Town::add_queue -----------//
  1561. //--------- Begin of function Town::remove_queue ---------//
  1562. void Town::remove_queue(char skillId)
  1563. {
  1564. for(int i=train_queue_count-1; i>=0; i--)
  1565. {
  1566. if(train_queue_skill_array[i] == skillId)
  1567. {
  1568. err_when(train_queue_count > MAX_TRAIN_QUEUE);
  1569. m.del_array_rec(train_queue_skill_array, train_queue_count, sizeof(train_queue_skill_array[0]), i+1);
  1570. m.del_array_rec(train_queue_race_array, train_queue_count, sizeof(train_queue_race_array[0]), i+1);
  1571. train_queue_count--;
  1572. return;
  1573. }
  1574. }
  1575. if(train_unit_recno)
  1576. {
  1577. Unit *unitPtr = unit_array[train_unit_recno];
  1578. if((unitPtr->skill).skill_id==skillId)
  1579. cancel_train_unit();
  1580. }
  1581. }
  1582. //----------- End of function Town::remove_queue -----------//
  1583. //--------- Begin of function Town::disp_debug_resistance ---------//
  1584. //
  1585. void Town::disp_debug_resistance(int refreshFlag)
  1586. {
  1587. if( nation_recno == nation_array.player_recno ) // not for player's own town
  1588. return;
  1589. if( refreshFlag==INFO_REPAINT )
  1590. vga.d3_panel_up( INFO_X1, INFO_Y2-50, INFO_X2, INFO_Y2 );
  1591. //------ display resistance (only for independent town) -----//
  1592. int x=INFO_X1+10, y=INFO_Y2-47;
  1593. if( nation_recno ==0 )
  1594. {
  1595. int raceId = race_filter(browse_race.recno());
  1596. for( int i=1 ; i<=nation_array.size() ; i++, x+=28 )
  1597. {
  1598. if( nation_array.is_deleted(i) )
  1599. continue;
  1600. if( refreshFlag==INFO_REPAINT )
  1601. vga_front.bar( x, y, x+18, y+16, nation_array[i]->nation_color );
  1602. font_san.put( x, y+18, (int) race_resistance_array[raceId-1][i-1], 1, x+19 );
  1603. font_san.put( x, y+32, (int) race_target_resistance_array[raceId-1][i-1], 1, x+19 );
  1604. }
  1605. }
  1606. else
  1607. {
  1608. //------ if this town is the nation's base town -----//
  1609. String str;
  1610. str = "Base: ";
  1611. str += is_base_town;
  1612. font_san.put( INFO_X1+10, y, str );
  1613. str = "Town recno: ";
  1614. str += town_recno;
  1615. font_san.put( INFO_X1+70, y, str );
  1616. str = "no_neighbor_space: ";
  1617. str += no_neighbor_space;
  1618. font_san.put( INFO_X1+10, y+16, str );
  1619. str = "quality of life: ";
  1620. str += quality_of_life;
  1621. font_san.disp( INFO_X1+10, y+32, str, INFO_X2-10 );
  1622. }
  1623. }
  1624. //----------- End of function Town::disp_debug_resistance -----------//
  1625. //--------- Begin of function Town::get_elected_race ---------//
  1626. int Town::get_selected_race()
  1627. {
  1628. if(browse_race.recno() > race_filter())
  1629. return 0;
  1630. return race_filter(browse_race.recno());
  1631. }
  1632. //----------- End of function Town::get_elected_race -----------//