Ikariam Enhanced UI

Enhancements for the user interface of Ikariam.

目前为 2017-11-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Ikariam Enhanced UI
  3. // @description Enhancements for the user interface of Ikariam.
  4. // @namespace Tobbe
  5. // @author Tobbe
  6. // @version 4.1
  7. // @license MIT License
  8. //
  9. // @name:de Ikariam Enhanced UI
  10. // @description:de Verbesserungen der Oberfläche von Ikariam.
  11. //
  12. // @run-at document-idle
  13. //
  14. //
  15. // @include /https?:\/\/s[0-9]*-[a-z]{2}\.ikariam\.gameforge\.com\/.*/
  16. //
  17. // @require https://greasyfork.org/scripts/5574-ikariam-core/code/Ikariam%20Core.js?version=229712
  18. //
  19. // @connect greasyfork.org
  20. //
  21. //
  22. // @resource de https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/de.json
  23. // @resource gr https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/gr.json
  24. // @resource fr https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/fr.json
  25. // @resource it https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/it.json
  26. // @resource lv https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/lv.json
  27. // @resource ru https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/ru.json
  28. // @resource tr https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/tr.json
  29. // @resource core_de https://resources.ikascripts.de/IkariamCore/v3.1/core_de.json
  30. // @resource core_de_settings https://resources.ikascripts.de/IkariamCore/v3.1/core_de_settings.json
  31. // @resource core_fr https://resources.ikascripts.de/IkariamCore/v3.1/core_fr.json
  32. // @resource core_fr_settings https://resources.ikascripts.de/IkariamCore/v3.1/core_fr_settings.json
  33. // @resource core_gr https://resources.ikascripts.de/IkariamCore/v3.1/core_gr.json
  34. // @resource core_gr_settings https://resources.ikascripts.de/IkariamCore/v3.1/core_gr_settings.json
  35. // @resource core_it https://resources.ikascripts.de/IkariamCore/v3.1/core_it.json
  36. // @resource core_it_settings https://resources.ikascripts.de/IkariamCore/v3.1/core_it_settings.json
  37. // @resource core_lv https://resources.ikascripts.de/IkariamCore/v3.1/core_lv.json
  38. // @resource core_lv_settings https://resources.ikascripts.de/IkariamCore/v3.1/core_lv_settings.json
  39. // @resource core_ru https://resources.ikascripts.de/IkariamCore/v3.1/core_ru.json
  40. // @resource core_ru_settings https://resources.ikascripts.de/IkariamCore/v3.1/core_ru_settings.json
  41. // @resource core_tr https://resources.ikascripts.de/IkariamCore/v3.1/core_tr.json
  42. // @resource core_tr_settings https://resources.ikascripts.de/IkariamCore/v3.1/core_tr_settings.json
  43. //
  44. // @grant unsafeWindow
  45. // @grant GM_setValue
  46. // @grant GM.setValue
  47. // @grant GM_getValue
  48. // @grant GM.getValue
  49. // @grant GM_deleteValue
  50. // @grant GM.deleteValue
  51. // @grant GM_listValues
  52. // @grant GM.listValues
  53. // @grant GM_getResourceText
  54. // @grant GM.getResourceText
  55. // @grant GM_xmlhttpRequest
  56. // @grant GM.xmlHttpRequest
  57. //
  58. // @bug Opera & Chrome Zooming with the mouse is not possible with "Shift" as access key.
  59. // @bug Opera & Chrome No updating of the missing resources is possible due to a missing modification listener.
  60. // @bug All The selected island is not centered in world view.
  61. // @bug All If you are zooming to more than 100%, the view is not centered correctly after a page reload.
  62. //
  63. // @history 4.1 Release: 12.11.2017
  64. // @history 4.1 Core: Update to Version 3.1 - support translations in Greasemonkey 4.0
  65. //
  66. // @history 4.0 Release: 10.11.2017
  67. // @history 4.0 Core: Update to Version 3.0 - Adjust to work with Greasemonkey 4.0 and Firefox 57
  68. // @history 4.0 Change: Adjust the script to work with Greasemonkey 4.0 and Firefox 57.
  69. // @history 4.0 Bugfix: Global messages break embedded messages preview.
  70. // @history 4.0 Bugfix: Formatting of income table was changed.
  71. //
  72. // @history 3.4 Release: 19.02.2017
  73. // @history 3.4 Core: Update to Version 2.3.3 - Bug fix (crew conversion broken)
  74. // @history 3.4 Feature: Up to 60 characters of messages are displayed in the message overview.
  75. // @history 3.4 Feature: Link barracks / shipyard from troop overview / dismiss units screen.
  76. // @history 3.4 Bugfix: No jumping header bar anymore due to MMO links.
  77. // @history 3.4 Bugfix: Troop information was displayed incorrectly.
  78. //
  79. // @history 3.3 Release: 05.06.2016
  80. // @history 3.3 Feature: Add @connect information to avoid requests from Tampermonkey.
  81. // @history 3.3 Feature: Daily expenses in resource information if amount is negative.
  82. // @history 3.3 Bugfix: Tooltip formatting for resource information broken.
  83. // @history 3.3 Bugfix: Formatting of direct tooltip in military advisor broken.
  84. // @history 3.3 Bugfix: Foreign troops are incorrect displayed in troop information.
  85. //
  86. // @history 3.2.2 Release: 02.02.2016
  87. // @history 3.2.2 Core: Update to Version 2.3.2 - Bug fix (permanent reload of crew conversion)
  88. //
  89. // @history 3.2.1 Release: 27.01.2016
  90. // @history 3.2.1 Core: Update to Version 2.3.1 - Bug fixes
  91. //
  92. // @history 3.2 Release: 27.01.2016
  93. // @history 3.2 Core: Update to Version 2.3 - Bug fixes
  94. // @history 3.2 Feature: Let the script also run on SSL encripted Ikariam page.
  95. // @history 3.2 Bugfix: In very rare cases it was possible that the script was to fast and thus did not work.
  96. // @history 3.2 Language: French translation added (incomplete).
  97. //
  98. // @history 3.1 Release: 14.10.2015
  99. // @history 3.1 Core: Update to Version 2.2 - Bug fixes and user specific options
  100. // @history 3.1 Feature: Player specific signatures in messages.
  101. // @history 3.1 Change: Remove easy circular message functionality as it is implemented directly in Ikariam now.
  102. // @history 3.1 Language: Turkish translation added (incomplete).
  103. //
  104. // @history 3.0.3 Release: 20.03.2015
  105. // @history 3.0.3 Bugfix: Town name in unit information incorrect.
  106. //
  107. // @history 3.0.2 Release: 08.03.2015
  108. // @history 3.0.2 Bugfix: Wrong time display for last reset of highscore information.
  109. // @history 3.0.2 Bugfix: Start piracy raid icon was resized.
  110. //
  111. // @history 3.0.1 Release: 07.03.2015
  112. // @history 3.0.1 Language: Updated Greek translation.
  113. // @history 3.0.1 Bugfix: Language key in message options.
  114. // @history 3.0.1 Bugfix: Alliance member data stored at same place for all alliance members.
  115. //
  116. // @history 3.0 Release: 05.03.2015
  117. // @history 3.0 Language: Russian translation added (incomplete).
  118. // @history 3.0 Language: Italian translation added (incomplete).
  119. // @history 3.0 Language: Greek translation added (incomplete).
  120. // @history 3.0 Change: Implementation of Ikariam Core - rewrote the complete code.
  121. // @history 3.0 Change: Cleared the update history to use the Ikariam Core labels.
  122. // @history 3.0 Bugfix: Diverse graphic errors.
  123. // @history 3.0 Bugfix: Broken in Firefox and Chrome.
  124. // @history 3.0 Due to rename of script: Manually deleting old script necessary.
  125. //
  126. // @history 2.6 Release: 12.10.2014
  127. // @history 2.6 Bugfix: Script options were broken.
  128. //
  129. // @history 2.6 Release: 19.08.2014
  130. // @history 2.5 Bugfix: Game language is recognized again.
  131. // @history 2.5 Bugfix: Works now in Greasemonkey 2.0+
  132. // @history 2.5 Change: Checks now for updates on Greasy Fork.
  133. // @history 2.5 Removed code parts for mobile version.
  134. // @history 2.5 Removed alliance page improvement, as fixed in Ikariam v0.5.13
  135. //
  136. // @history 2.6 Release: 11.09.2013
  137. // @history 2.4 Bugfix: New Ikariam domain -> script can now be used with this domain
  138. //
  139. // @history 2.3 Release: 12.04.2013
  140. // @history 2.3 Feature: Formatting troop lists for posting in forums / personal messages.
  141. // @history 2.3 Feature: Filling level of warehouse as bar in town view.
  142. // @history 2.3 Feature: Link to mines / town hall when clicking on resources / citizens.
  143. // @history 2.3 Change: New versioning system.
  144. // @history 2.3 Bugfix: Some characters in links were not decoded correctly.
  145. // @history 2.3 Bugfix: Watching a foreign city causes a abortion of the script.
  146. // @history 2.3 Bugfix: The city dropdown sometimes was zoomed in world view.
  147. // @history 2.3 Bugfix: Removed obsolete CSS styles for Firefox.
  148. // @history 2.3 Adjustments in the language files.
  149. // @history 2.3 Violent Monkey brings Greasemonkey functions to Opera.
  150. //
  151. // @history 2.2.1 Release: 11.10.2012
  152. // @history 2.2.1 Feature: Smaller icons in direct military tooltip.
  153. // @history 2.2.1 Bugfix: Problems with update check and version numbers >= 10.
  154. // @history 2.2.1 Bugfix: Problems with another script.
  155. // @history 2.2.1 Bugfix: Problems with a wrong style in island view.
  156. //
  157. // @history 2.2 Release: 10.10.2012
  158. // @history 2.2 Feature: Message signature can be set.
  159. // @history 2.2 Feature: Button for faster sending of circular messages.
  160. // @history 2.2 Feature: Make links in messages clickable.
  161. // @history 2.2 Feature: Show town information of colonizing cities.
  162. // @history 2.2 Feature: Information about cargo / fleets is displayed directly in military view.
  163. // @history 2.2 Feature: Script options: Sections on the script tab can be folded.
  164. // @history 2.2 Bugfix: Tooltips with mouseover were not clickable anymore.
  165. // @history 2.2 Changes in code for better overview.
  166. //
  167. // @history 2.1.1 Release: 01.10.2012
  168. // @history 2.1.1 Feature: Different styles for income in town view.
  169. // @history 2.1.1 Feature: Remaining resources after upgrade.
  170. // @history 2.1.1 Feature: Improved style for external alliance pages.
  171. // @history 2.1.1 Feature: Refresh the missing / remaining resources in construction view automatically.
  172. //
  173. // @history 2.1 Release: 23.09.2012
  174. // @history 2.1 Feature: Show the missing resources in construction view.
  175. // @history 2.1 Feature: Show the hourly income directly in town view and add the daily production as popup.
  176. // @history 2.1 Feature: Don't center town information in the town advisor.
  177. // @history 2.1 Feature: Save the highscore data of alliance members and compare it with the actual value.
  178. // @history 2.1 Bugfix: There was an error with a missing language package and seperators.
  179. // @history 2.1 Bugfix: Some things in worldview were not resized correctly.
  180. // @history 2.1 Prevent more than one script execution.
  181. // @history 2.1 Prevent more than one script option panel (the script option panel now is usable for other scripts, too).
  182. //
  183. // @history 2.0.1 Release: 27.08.2012
  184. // @history 2.0.1 Bugfix: Zooming was broken.
  185. // @history 2.0.1 Bugfix: Dropdown menus created by the script were broken.
  186. // @history 2.0.1 Bugfix: Tooltips in in Alliance / Military view were not shown correctly.
  187. //
  188. // @history 2.0 Release: 18.07.2012
  189. // @history 2.0 Language: Latvian translation
  190. // @history 2.0 Feature: Cross-browser compatibility.
  191. // @history 2.0 Feature: Possibility to hide the update hint for a new script version.
  192. // @history 2.0 Bugfix: Resizing the owner state in world view was broken.
  193. // @history 2.0 Some changes in the code for easier copying of functions which should be used by more than one script.
  194. //
  195. // @history 1.7 Release: 12.06.2012
  196. // @history 1.7 Feature: Resizing banners when zooming is possible in city view, too.
  197. // @history 1.7 Feature: The zoom buttons are available in world view, too.
  198. // @history 1.7 Feature: Zooming with the mouse scroll is possible again (now with key, standard is ctrl).
  199. // @history 1.7 Change: Changes in the option panel due to the new zooming function features.
  200. // @history 1.7 Bugfix: If resizing is enabled, zooming with the buttons will resize the banners, too.
  201. // @history 1.7 Bugfix: The chat will not cause to much executions of script functions.
  202. // @history 1.7 The language texts are integrated as resources, so that there is shorter code.
  203. // @history 1.7 Replace the GM_* functions by myGM.* to expand them easy and add new.
  204. //
  205. // @history 1.6 Release: 05.06.2012
  206. // @history 1.6 Feature: Possibility to hide only the bird swarm animation.
  207. // @history 1.6 Feature: Easier upkeep reduction table.
  208. // @history 1.6 Feature: Enhanced zoom function using the Ikariam zoom function.
  209. // @history 1.6 Due to the use of Ikariam functions the code could be reduced.
  210. // @history 1.6 Code enhancements for shorter code.
  211. //
  212. // @history 1.5.1.1 Release: 25.05.2012
  213. // @history 1.5.1.1 Bugfix: Not all occurrences of hidden were changed.
  214. //
  215. // @history 1.5.1 Release: 24.05.2012
  216. // @history 1.5.1 Bugfix: Name of a class (hidden) is used by GF.
  217. //
  218. // @history 1.5 Release: 24.05.2012
  219. // @history 1.5 Feature: Options panel to enable/disable funtions and set settings.
  220. // @history 1.5 Feature: Update interval can be set.
  221. // @history 1.5 Feature: Manually check for updates.
  222. // @history 1.5 Feature: Zoom function without resizing the whole view.
  223. // @history 1.5 Feature: Move loading circle to another position.
  224. // @history 1.5 Feature: Show tooltip in alliance / military view on mouseover.
  225. // @history 1.5 Change: Code better commented. More comments, so that it is easier to understand.
  226. // @history 1.5 Bugfix: Changed *.gif to *.png.
  227. // @history 1.5 Version numbers adjusted.
  228. //
  229. // @history 1.4.1 Release: 01.05.2012
  230. // @history 1.4.1 Feature: Support for mobile interface.
  231. // @history 1.4.1 Bugfix: Fixed bug with scrollbar in finances view.
  232. //
  233. // @history 1.4 Release: 20.04.2012
  234. // @history 1.4 Feature: Ready for 0.5.0, but also supports 0.4.5 furthermore.
  235. // @history 1.4 Feature: Implemented support for different languages.
  236. // @history 1.4 Feature: Enhanced script updater.
  237. // @history 1.4 Change: Cleaned up code.
  238. // @history 1.4 Change: Rename the script to "Enhanced UI".
  239. // @history 1.4 Change: Change the namespace to "Tobbe".
  240. // @history 1.4 Because of the change of namespace and name you have to delete the old script manually!
  241. //
  242. // @history 1.3.3 Release: 11.04.2011
  243. // @history 1.3.3 Bugfix: Problem with negative numbers and 0.4.2.4 fixed.
  244. //
  245. // @history 1.3.2 Release: 15.01.2011
  246. // @history 1.3.2 Feature: Own script updater.
  247. // @history 1.3.2 Change: Remove everything what refered to other scripts.
  248. //
  249. // @history 1.3.1 Release: 15.01.2011
  250. // @history 1.3.1 Change: New script updater.
  251. //
  252. // @history 1.3 Release: 14.01.2011
  253. // @history 1.3 Change: Remove the script updater (Because of the problem with Greasemonkey scripts).
  254. //
  255. // @history 1.2.1 Release: 28.12.2010
  256. // @history 1.2.1 Change: New style of update panel.
  257. // @history 1.2.1 Bugfix: Bug with ',' as seperator fixed.
  258. //
  259. // @history 1.2 Release: 09.10.2010
  260. // @history 1.2 Feature: Income in 24h added.
  261. // @history 1.2 Change: Cleaned up code.
  262. //
  263. // @history 1.1 Release: 13.04.2010
  264. // @history 1.1 Feature: Update check implemented.
  265. //
  266. // @history 1.0 Release: 12.04.2010
  267. // @history 1.0 Initial release.
  268. // ==/UserScript==
  269.  
  270. /**
  271. * Instantiate a new set of enhancement functions.
  272. * {@link https://greasyfork.org/scripts/4369-enhanced-ui Script on Greasy Fork}
  273. * {@link https://github.com/IkaScripts/IkariamEnhancedUI Script on GitHub}
  274. *
  275. * @version 4.1
  276. * @author Tobbe <contact@ikascripts.de>
  277. *
  278. * @global
  279. *
  280. * @class
  281. * @classdesc Enhancements for the user interface of Ikariam.
  282. *
  283. * @param {IkariamCore} $
  284. * An instance of the Ikariam Core.
  285. */
  286. function EnhancedUI(IC) {
  287. /**
  288. * Script toolbar.
  289. *
  290. * @type {element}
  291. */
  292. var ge_toolbar = IC.myGM.addElement('div', IC.myGM.$('#GF_toolbar'), { 'id': 'toolbar' }, true, IC.myGM.$('#GF_toolbar ul'));
  293. IC.myGM.addStyle(
  294. '#GF_toolbar > ul { width: auto !important; text-align: center !important; pointer-events: none; } \
  295. #GF_toolbar > ul > * { pointer-events: auto; } \
  296. #GF_toolbar #mmoNewsticker { display: inline-block !important; position: relative !important; } \
  297. #GF_toolbar #mmoNewsticker > ul { width: 300px !important; } \
  298. #' + IC.myGM.prefix + 'toolbar { float: right; } \
  299. #' + IC.myGM.prefix + 'toolbar > div { display: inline-block; position: relative; float: right; margin: 0px 5px; }',
  300. 'scriptToolbar'
  301. );
  302. IC.Options.addWrapper('diverseOptions', IC.Language.$('diverse.options.wrapperTitle'));
  303. IC.con.groupCollapsed('IkariamEnhancedUI initalization ...');
  304. IC.con.logTimeStamp('IkariamEnhancedUI: toolbar and general styles created');
  305. // General functions to enhance the view.
  306. (function() {
  307. IC.Options.addWrapper('enhancedView', IC.Language.$('view.options.wrapperTitle'));
  308. // Move the loading circle to the breadcrumb area.
  309. IC.Options.addCheckbox('moveLoadingCircle', 'enhancedView', 1, true, IC.Language.$('view.options.moveLoadingCircle'), {
  310. changeCallback: function(ib_newValue) {
  311. if(ib_newValue === true) {
  312. IC.myGM.addStyle(
  313. '#js_worldBread { margin-left: 16px !important; } \
  314. #loadingPreview { transform: scale(0.5); -webkit-transform: scale(0.5); left: 35px !important; top: 141px !important; }',
  315. 'enhancedView_moveLoadingCircle'
  316. );
  317. return;
  318. }
  319. IC.myGM.removeStyle('enhancedView_moveLoadingCircle');
  320. }
  321. });
  322. // Hide the flying bird swarm.
  323. IC.Options.addCheckbox('hideBirds', 'enhancedView', 1, true, IC.Language.$('view.options.hideBirds'), {
  324. changeCallback: function(ib_newValue) {
  325. if(ib_newValue === true) {
  326. IC.myGM.addStyle(
  327. '.bird_swarm { display: none; }',
  328. 'enhancedView_hideBirds'
  329. );
  330. return;
  331. }
  332. IC.myGM.removeStyle('enhancedView_hideBirds');
  333. }
  334. });
  335. // Bind the town name and date to the top of the row in the town advisor.
  336. IC.Options.addCheckbox('noVerticalCenterInTownAdvisor', 'enhancedView', 1, true, IC.Language.$('view.options.noVerticalCenterInTownAdvisor'), {
  337. changeCallback: function(ib_newValue) {
  338. if(ib_newValue === true) {
  339. IC.myGM.addStyle(
  340. '#inboxCity td { vertical-align: top !important; }',
  341. 'enhancedView_noVerticalCenterInTownAdvisor'
  342. );
  343. return;
  344. }
  345. IC.myGM.removeStyle('enhancedView_noVerticalCenterInTownAdvisor');
  346. }
  347. });
  348. })();
  349. IC.con.logTimeStamp('IkariamEnhancedUI: view functions created');
  350. // Functions for the island view.
  351. (function() {
  352. /**
  353. * Storage for the colonizing city info functions.
  354. *
  355. * @type {object}
  356. */
  357. var _go_colonizingCityInfo = new function() {
  358. /**
  359. * Add the link to show the colonizing city information.
  360. */
  361. var _lf_doShowColonizingCityInfo = function() {
  362. var la_colonizingCities = IC.myGM.$$('.level0');
  363. la_colonizingCities.forEach(function(le_colonizingCity) {
  364. var ls_locationId = le_colonizingCity.id.replace(/\D/g, '');
  365. var ls_cityId = IC.ika.getScreen().data.cities[ls_locationId].id;
  366. IC.myGM.$('#js_cityLocation' + ls_locationId + 'Link').href = '?view=cityDetails&destinationCityId=' + ls_cityId;
  367. });
  368. };
  369. /**
  370. * Remove the link to show the colonizing city information.
  371. */
  372. var _lf_doHideColonizingCityInfo = function() {
  373. var la_colonizingCityLinks = IC.myGM.$$('.level0 .link_img');
  374. la_colonizingCityLinks.forEach(function(le_colonizingCityLink) {
  375. le_colonizingCityLink.href = '';
  376. });
  377. };
  378. /**
  379. * Update the settings to execute the callback or delete the handler.
  380. *
  381. * @param {boolean} ib_showColonizingCityInfo
  382. * If the user selected the checkbox to show the colonizing city info.
  383. */
  384. this.updateSettings = function(ib_showColonizingCityInfo) {
  385. if(IC.Ikariam.view !== 'island')
  386. return;
  387. if(ib_showColonizingCityInfo === true) {
  388. IC.RefreshHandler.add('*', 'showColonizingCityInfo', _lf_doShowColonizingCityInfo);
  389. _lf_doShowColonizingCityInfo();
  390. return;
  391. }
  392. IC.RefreshHandler.remove('*', 'showColonizingCityInfo');
  393. _lf_doHideColonizingCityInfo();
  394. };
  395. };
  396. // Retrieve information about colonies during colonization.
  397. IC.Options.addCheckbox('showColonizingCityInfo', 'diverseOptions', 1, true, IC.Language.$('island.options.showColonizingCityInfo'), { changeCallback: _go_colonizingCityInfo.updateSettings });
  398. // Add a divider line.
  399. IC.Options.addLine('diverseOptions', 1);
  400. })();
  401. IC.con.logTimeStamp('IkariamEnhancedUI: island functions created');
  402. // Functions for the finance popup.
  403. (function(){
  404. /**
  405. * Some general functions for the finance view enhancements.
  406. *
  407. * @type {object}
  408. */
  409. var _go_generalFunctions = new function() {
  410. /**
  411. * Extract the current income in the finance popup.
  412. *
  413. * @return {int}
  414. * The current income.
  415. */
  416. this.getIncome = function() {
  417. var le_incomeCell = IC.myGM.$$('.hidden')[IC.myGM.$$('.hidden').length - 1];
  418. while(le_incomeCell.firstChild.firstChild)
  419. le_incomeCell = le_incomeCell.firstChild;
  420. return IC.Ikariam.getInt(le_incomeCell.innerHTML);
  421. };
  422. /**
  423. * Create a new table row.
  424. *
  425. * @param {element} ie_parentTable
  426. * The table to add the row to.
  427. * @param {string[]} ia_classes
  428. * The class(es) of the table row. Set to null if no class should be set.
  429. * @param {object[]} ia_cells
  430. * The data for the table cells. Both properties of each cell are optional. If the cell object is empty, an empty cell is created.
  431. * Signature: <code>[{ className: ['class1', 'class2', ...], text: 'cellContent' }]</code>
  432. * @param {boolean} ib_isTableHeadRow
  433. * If the cells should be table header cells (th).
  434. *
  435. * @return {element}
  436. * The created row.
  437. */
  438. this.createTableRow = function(ie_parentTable, ia_classes, ia_cells, ib_isTableHeadRow) {
  439. var re_newRow = IC.myGM.addElement('tr', ie_parentTable, { classes: ia_classes });
  440. var ls_cellType = 'td';
  441. if(!!ib_isTableHeadRow)
  442. ls_cellType = 'th';
  443. for(var i = 0; i < ia_cells.length; i++) {
  444. var lo_options = {
  445. 'classes': ia_cells[i].className
  446. };
  447. if(!!ia_cells[i].text === true)
  448. lo_options['innerHTML'] = ia_cells[i].text;
  449. IC.myGM.addElement(ls_cellType, re_newRow, lo_options);
  450. }
  451. return re_newRow;
  452. };
  453. };
  454. /**
  455. * Storage for the income on top functions.
  456. *
  457. * @type {object}
  458. */
  459. var _go_incomeOnTop = new function() {
  460. /**
  461. * Callback to show the income on top.
  462. */
  463. var _lf_doShowIncomeOnTop = function() {
  464. var le_summaryTable = IC.myGM.$('.table01 tbody');
  465. var li_income = _go_generalFunctions.getIncome();
  466. var la_incomeCells = [
  467. { className: ['sigma'], text: IC.Language.$('finance.income.perHour') },
  468. { className: ['nowrap', 'res'], text: IC.Ikariam.formatToIkaNumber(li_income) }
  469. ];
  470. _go_generalFunctions.createTableRow(le_summaryTable, [], la_incomeCells);
  471. la_incomeCells[0].text = IC.Language.$('finance.income.perDay');
  472. la_incomeCells[1].text = IC.Ikariam.formatToIkaNumber(li_income * 24);
  473. _go_generalFunctions.createTableRow(le_summaryTable, [], la_incomeCells);
  474. var le_premiumCell = IC.myGM.$('.premiumOffer', le_summaryTable);
  475. le_premiumCell.rowSpan = le_premiumCell.rowSpan + 2;
  476. // Adjust the size of the Scrollbar.
  477. IC.ika.controller.adjustSizes();
  478. };
  479. /**
  480. * Update the settings to execute the callback or delete the handler.
  481. *
  482. * @param {boolean} ib_showIncomeOnTop
  483. * If the user selected the checkbox to show the income on top.
  484. */
  485. this.updateSettings = function(ib_showIncomeOnTop) {
  486. if(ib_showIncomeOnTop === true) {
  487. IC.RefreshHandler.add('finances', 'showIncomeOnTop', _lf_doShowIncomeOnTop);
  488. return;
  489. }
  490. IC.RefreshHandler.remove('finances', 'showIncomeOnTop');
  491. };
  492. };
  493. /**
  494. * Storage for the short upkeep reduction table functions.
  495. *
  496. * @type {object}
  497. */
  498. var _go_shortUpkeepReductionTable = new function() {
  499. /**
  500. * Extract the data from the old tables.
  501. *
  502. * @param {element[]} ia_oldUpkeepReductionTables
  503. * The old upkeep tables to collapse.
  504. *
  505. * @return {object[]}
  506. * The data for the table rows.
  507. * Signature:
  508. * <code>[{
  509. * rows: [
  510. * { reason : 'reason', basicUpkeep: int, supplyUpkeep: int, result: int }
  511. * ]
  512. * priorToReduction: int
  513. * income: int
  514. * }]</code>
  515. */
  516. var _lf_getData = function(ia_oldUpkeepReductionTables) {
  517. var ro_data = {
  518. rows: [],
  519. priorToReduction: IC.Ikariam.getInt(IC.myGM.$('td.hidden', ia_oldUpkeepReductionTables[2]).innerHTML),
  520. income: _go_generalFunctions.getIncome()
  521. };
  522. // Get the data for the troops and ships redution rows.
  523. for(var i = 0; i < 3; i++) {
  524. var le_basicUpkeepCell = IC.myGM.$$('.alt.bottomLine td.hidden, .result td.hidden', ia_oldUpkeepReductionTables[0])[i];
  525. var le_supplyUpkeepCell = IC.myGM.$$('.alt.bottomLine td.hidden, .result td.hidden', ia_oldUpkeepReductionTables[1])[i];
  526. var li_basicUpkeep = IC.Ikariam.getInt(le_basicUpkeepCell.innerHTML);
  527. var li_supplyUpkeep = IC.Ikariam.getInt(le_supplyUpkeepCell.innerHTML);
  528. var lo_row = {
  529. reason: IC.Language.$('finance.upkeep.reason.' + i),
  530. basicUpkeep: li_basicUpkeep,
  531. supplyUpkeep: li_supplyUpkeep,
  532. result: li_basicUpkeep + li_supplyUpkeep
  533. };
  534. ro_data.rows.push(lo_row);
  535. }
  536. return ro_data;
  537. };
  538. /**
  539. * Prepare the table rows for easy adding to the new table.
  540. *
  541. * @param {element[]} ia_oldUpkeepReductionTables
  542. * The old upkeep tables to collapse.
  543. *
  544. * @return {object[]}
  545. * The data for the table rows.
  546. * Signature:
  547. * <code>[{
  548. * classes: 'class' || ['class1', 'class2', ...]
  549. * isHeadRow: true || false
  550. * cells: [
  551. * { className: 'class' || ['class1', 'class2', ...], text: 'cellContent' (optional) }
  552. * ]
  553. * }]</code>
  554. */
  555. var _lf_prepareTableRows = function(ia_oldUpkeepReductionTables) {
  556. var lo_data = _lf_getData(ia_oldUpkeepReductionTables);
  557. var ra_tableRows = [];
  558. // Header
  559. ra_tableRows.push({
  560. classes: [],
  561. isHeadRow: true,
  562. cells: [
  563. { className: ['city', 'left'] },
  564. { className: ['left'], text: IC.Language.$('finance.upkeep.basic') },
  565. { className: ['left'], text: IC.Language.$('finance.upkeep.supply') },
  566. { className: ['left'], text: IC.Language.$('finance.upkeep.result') }
  567. ]
  568. });
  569. // Income without reduction
  570. ra_tableRows.push({
  571. classes: ['alt', 'bottomLine'],
  572. isHeadRow: false,
  573. cells: [
  574. { className: ['city', 'left'], text: IC.Language.$('finance.income.start') },
  575. { className: ['nowrap', 'res'] },
  576. { className: ['nowrap', 'res'] },
  577. { className: ['nowrap', 'res'], text: IC.Ikariam.formatToIkaNumber(lo_data.priorToReduction) }
  578. ]
  579. });
  580. // Income reduction
  581. lo_data.rows.forEach(function(io_row, ii_index) {
  582. var trClass = [];
  583. if(ii_index % 2 === 1)
  584. trClass = ['alt', 'bottomLine'];
  585. ra_tableRows.push({
  586. classes: trClass,
  587. isHeadRow: false,
  588. cells: [
  589. { className: ['city', 'left'], text: io_row.reason },
  590. { className: ['nowrap', 'res'], text: IC.Ikariam.formatToIkaNumber(-io_row.basicUpkeep) },
  591. { className: ['nowrap', 'res'], text: IC.Ikariam.formatToIkaNumber(-io_row.supplyUpkeep) },
  592. { className: ['nowrap', 'res'], text: IC.Ikariam.formatToIkaNumber(-io_row.result) }
  593. ]
  594. });
  595. });
  596. // Result
  597. ra_tableRows.push({
  598. classes: ['result'],
  599. isHeadRow: false,
  600. cells: [
  601. { className: ['sigma', 'left'], text: '<img alt="Summe" src="skin/layout/sigma.png">' },
  602. { className: ['nowrap', 'res'] },
  603. { className: ['nowrap', 'res'] },
  604. { className: ['nowrap', 'res'], text: IC.Ikariam.formatToIkaNumber(lo_data.income) }
  605. ]
  606. });
  607. return ra_tableRows;
  608. };
  609. /**
  610. * Create the new upkeep reduction table.
  611. *
  612. * @param {element[]} ia_oldUpkeepReductionTables
  613. * The old upkeep tables.
  614. */
  615. var _lf_createNewTable = function(ia_oldUpkeepReductionTables) {
  616. var le_shortTable = IC.myGM.addElement('table', ia_oldUpkeepReductionTables[0].parentNode, {
  617. 'id': 'balance',
  618. 'classes': ['table01', 'border']
  619. }, null, ia_oldUpkeepReductionTables[0]);
  620. var la_tableRows = _lf_prepareTableRows(ia_oldUpkeepReductionTables);
  621. la_tableRows.forEach(function(io_rowData) {
  622. _go_generalFunctions.createTableRow(le_shortTable, io_rowData.classes, io_rowData.cells, io_rowData.isHeadRow);
  623. });
  624. IC.myGM.addElement('hr', ia_oldUpkeepReductionTables[0].parentNode, {}, null, ia_oldUpkeepReductionTables[0]);
  625. };
  626. /**
  627. * Toggle the status of an old upkeep table (collapsed / non-collapsed).
  628. */
  629. var _lf_toggleUpkeepReductionTable = function() {
  630. IC.myGM.toggleShowHideButton(this);
  631. var la_rows = IC.myGM.$$('tr:not(:first-child)', this.parentNode.parentNode.parentNode);
  632. la_rows.forEach(function(ie_row) {
  633. ie_row.classList.toggle('invisible');
  634. });
  635. // Adjust the size of the Scrollbar.
  636. IC.ika.controller.adjustSizes();
  637. };
  638. /**
  639. * Minimize the old upkeep tables and make them collapsable.
  640. *
  641. * @param {element[]} ia_oldUpkeepReductionTables
  642. * The old upkeep tables to collapse.
  643. */
  644. var _lf_minimizeOldTables = function(ia_oldUpkeepReductionTables) {
  645. for(var i = 0; i < ia_oldUpkeepReductionTables.length; i++) {
  646. var la_rows = IC.myGM.$$('tr', ia_oldUpkeepReductionTables[i]);
  647. la_rows.forEach(function(ie_row, ii_index) {
  648. if(ii_index !== 0)
  649. ie_row.classList.add('invisible');
  650. });
  651. var le_buttonParent = IC.myGM.$('th', la_rows[0]);
  652. IC.myGM.addElement('div', le_buttonParent, {
  653. 'class': 'maximizeImg',
  654. 'style': [['cssFloat', 'left']],
  655. 'title': IC.Language.$('general.expand'),
  656. 'click': _lf_toggleUpkeepReductionTable
  657. }, null, le_buttonParent.firstChild);
  658. }
  659. };
  660. /**
  661. * Callback to show the short upkeep reduction table.
  662. */
  663. var _lf_doShowShortTable = function() {
  664. var la_oldUpkeepReductionTables = IC.myGM.$$('.upkeepReductionTable');
  665. _lf_createNewTable(la_oldUpkeepReductionTables);
  666. _lf_minimizeOldTables(la_oldUpkeepReductionTables);
  667. // Adjust the size of the Scrollbar.
  668. IC.ika.controller.adjustSizes();
  669. };
  670. /**
  671. * Update the settings to execute the callback or delete the handler.
  672. *
  673. * @param {boolean} ib_showShortTable
  674. * If the user selected the checkbox to show the short upkeep reduction table.
  675. */
  676. this.updateSettings = function(ib_showShortTable) {
  677. if(ib_showShortTable === true) {
  678. IC.RefreshHandler.add('finances', 'shortUpkeepReductionTable', function() { _lf_doShowShortTable(); });
  679. return;
  680. }
  681. IC.RefreshHandler.remove('finances', 'shortUpkeepReductionTable');
  682. };
  683. };
  684. // Show the income also on top in finance popup.
  685. IC.Options.addCheckbox('showIncomeOnTop', 'diverseOptions', 1, true, IC.Language.$('finance.options.showIncomeOnTop'), { changeCallback: _go_incomeOnTop.updateSettings });
  686. // Short overview upkeep reduction table in finance popup.
  687. IC.Options.addCheckbox('shortUpkeepReductionTable', 'diverseOptions', 1, true, IC.Language.$('finance.options.shortUpkeepReductionTable'), { changeCallback: _go_shortUpkeepReductionTable.updateSettings });
  688. // Add a divider line.
  689. IC.Options.addLine('diverseOptions', 1);
  690. })();
  691. IC.con.logTimeStamp('IkariamEnhancedUI: finance functions created');
  692. // Functions for missing resources.
  693. (function() {
  694. /**
  695. * Storage for the missing ressources functions.
  696. *
  697. * @type {object}
  698. */
  699. var _go_showMissingResources = new function() {
  700. /**
  701. * Update the information in the missing resources wrappers.
  702. *
  703. * @param {boolean} ib_isUpdateView
  704. * If the update is in the update view.
  705. */
  706. var _lf_updateInformation = function(ib_isUpdateView) {
  707. var la_currentResources = [
  708. IC.ika.getModel().currentResources.resource, // Wood.
  709. IC.ika.getModel().currentResources[1], // Wine.
  710. IC.ika.getModel().currentResources[2], // Marble.
  711. IC.ika.getModel().currentResources[3], // Crystal.
  712. IC.ika.getModel().currentResources[4] // Sulfur.
  713. ];
  714. var lb_showPositiveNumbers = IC.Options.getOption('missingResources', 'showPositive') === true && ib_isUpdateView === true;
  715. var lb_showMissingColoured = IC.Options.getOption('missingResources', 'showColoured');
  716. var ls_resourcesPattern = '%resources%';
  717. if(ib_isUpdateView !== true)
  718. ls_resourcesPattern = ' (' + ls_resourcesPattern + ')';
  719. for(var i = 0; i < IC.Ikariam.resourceNames.length; i++) {
  720. var la_missingWrappers = IC.myGM.$$('.' + IC.myGM.prefix + 'missingResources' + IC.Ikariam.resourceNames[i]);
  721. if(!!la_missingWrappers) {
  722. for(var k = 0; k < la_missingWrappers.length; k++) {
  723. var le_neededWrapper = la_missingWrappers[k].previousSibling;
  724. var li_missing = la_currentResources[i] - IC.Ikariam.getInt(le_neededWrapper.nodeValue);
  725. if(li_missing < 0 || lb_showPositiveNumbers === true) {
  726. var ls_formattedMissingValue = IC.Ikariam.formatToIkaNumber(li_missing, lb_showMissingColoured, true);
  727. la_missingWrappers[k].innerHTML = ls_resourcesPattern.replace(/\%resources\%/, ls_formattedMissingValue);
  728. } else {
  729. la_missingWrappers[k].innerHTML = '';
  730. }
  731. }
  732. }
  733. }
  734. };
  735. /**
  736. * Add the missing resources wrappers.
  737. *
  738. * @param {boolean} ib_isUpdateView
  739. * If the wrappers are added to the update view.
  740. */
  741. var _lf_addMissingWrappers = function(ib_isUpdateView) {
  742. var ls_wrapperSelector = '#buildingGround .resources';
  743. if(ib_isUpdateView === true)
  744. ls_wrapperSelector = '#sidebar .resources';
  745. var la_wrappers = IC.myGM.$$(ls_wrapperSelector);
  746. for(var i = 0; i < la_wrappers.length; i++) {
  747. for(var k = 0; k < IC.Ikariam.resourceNames.length; k++) {
  748. var le_resourceNode = IC.myGM.$('.' + IC.Ikariam.resourceNames[k], la_wrappers[i]);
  749. if(!!le_resourceNode) {
  750. IC.myGM.addElement('span', le_resourceNode, { 'classes': ['missingResources', 'missingResources' + IC.Ikariam.resourceNames[k]] }, true);
  751. }
  752. }
  753. }
  754. _lf_updateInformation(ib_isUpdateView);
  755. };
  756. /**
  757. * Update the missing resources in building ground popup.
  758. */
  759. var _lf_doUpdateInBuildingView = function() {
  760. if(!IC.myGM.$('#buildingGround_c')) {
  761. IC.Observer.remove('missingResourcesBuilding');
  762. return;
  763. }
  764.  
  765. _lf_updateInformation(false);
  766. };
  767. /**
  768. * Update the missing resources in update view.
  769. */
  770. var _lf_doUpdateInUpdateView = function() {
  771. if(!IC.myGM.$('#buildingUpgrade')) {
  772. IC.Observer.remove('missingResourcesUpdate');
  773. return;
  774. }
  775.  
  776. _lf_updateInformation(true);
  777. };
  778. /**
  779. * Show the missing resources in building ground popup.
  780. */
  781. var _lf_doShowInBuildingGround = function() {
  782. _lf_addMissingWrappers(false);
  783. IC.Observer.add('missingResourcesBuilding', IC.myGM.$('#cityResources'), { childList: true, subtree: true }, _lf_doUpdateInBuildingView, _lf_doUpdateInBuildingView);
  784. };
  785. /**
  786. * Show the missing resources in update view.
  787. */
  788. var _lf_doShowInUpdateView = function() {
  789. if(!IC.myGM.$('#buildingUpgrade') || IC.myGM.$$('.' + IC.myGM.prefix + 'missingResources').length > 0)
  790. return;
  791. _lf_addMissingWrappers(true);
  792. IC.Observer.add('missingResourcesUpgrade', IC.myGM.$('#cityResources'), { childList: true, subtree: true }, _lf_doUpdateInUpdateView, _lf_doUpdateInUpdateView);
  793. };
  794. /**
  795. * Update the settings to execute the callback or delete the handler.
  796. *
  797. * @param {boolean} ib_showMissingResources
  798. * If the user selected the checkbox to show the missing resources info.
  799. */
  800. this.updateSettings = function(ib_showMissingResources) {
  801. if(ib_showMissingResources === true) {
  802. IC.RefreshHandler.add('buildingGround', 'showMissingResources', _lf_doShowInBuildingGround);
  803. IC.RefreshHandler.add('%', 'showMissingResources', _lf_doShowInUpdateView);
  804. IC.myGM.addStyle(
  805. '#sidebar #buildingUpgrade ul.resources li { width: 120px; } \
  806. #sidebar #buildingUpgrade ul.resources li.time { width: 60px !important; } \
  807. #sidebar .' + IC.myGM.prefix + 'missingResources { float: right; }',
  808. 'showMissingResources'
  809. );
  810. return;
  811. }
  812. IC.RefreshHandler.remove('buildingGround', 'showMissingResources');
  813. IC.RefreshHandler.remove('%', 'showMissingResources');
  814. IC.myGM.removeStyle('showMissingResources');
  815. };
  816. };
  817. IC.Options.addWrapper('missingResources', IC.Language.$('missingResources.options.wrapperTitle'));
  818. // Show missing resources in upgrade / building view.
  819. IC.Options.addCheckbox('show', 'missingResources', 1, true, IC.Language.$('missingResources.options.show'), { changeCallback: _go_showMissingResources.updateSettings });
  820. // Disable coloring of the missing resources.
  821. IC.Options.addCheckbox('showPositive', 'missingResources', 2, true, IC.Language.$('missingResources.options.showPositive'), {});
  822. // Show only missing ressources, not also remaining.
  823. IC.Options.addCheckbox('showColoured', 'missingResources', 2, true, IC.Language.$('missingResources.options.showColoured'), {});
  824. })();
  825. IC.con.logTimeStamp('IkariamEnhancedUI: missing resource functions created');
  826. // Functions for tooltips.
  827. (function() {
  828. /**
  829. * Storage for the autoshow tootips functions.
  830. *
  831. * @type {object}
  832. */
  833. var _go_autoshowTooltips = new function() {
  834. /**
  835. * General function for autowhow.
  836. *
  837. * @param {string} onclickWrapperClass
  838. * The class of the wrapper which has the onclik attribute set.
  839. */
  840. var _lf_autoshowTooltipsGeneral = function(onclickWrapperClass) {
  841. IC.myGM.$$('.' + onclickWrapperClass).forEach(function(onclickWrapper) {
  842. var onclickFunction = onclickWrapper.onclick;
  843. onclickWrapper.onclick = 'return false;';
  844. var newHandler = IC.myGM.$('.magnify_icon', onclickWrapper);
  845. if(!newHandler)
  846. newHandler = onclickWrapper;
  847. newHandler.addEventListener('mouseover', function(e) { IC.ika.controller.captureMousePosition(e); onclickFunction(e); }, true);
  848. });
  849. IC.myGM.$('.templateView .mainContent').addEventListener('click', function() { IC.win.$(document).trigger("closeExclusiveInfo"); }, true);
  850. };
  851. /**
  852. * Autmatically show tooltips in alliance member lists.
  853. */
  854. var _lf_doAutoshowTooltipsAlliance = function() {
  855. _lf_autoshowTooltipsGeneral('cityInfo');
  856. };
  857. /**
  858. * Autmatically show tooltips in military advisor.
  859. */
  860. var _lf_doAutoshowTooltipsMilitaryAdvisor = function() {
  861. if(IC.Options.getOption('moduleOptions', 'showDirectMilitaryTooltips') === true)
  862. return;
  863. _lf_autoshowTooltipsGeneral('spyMilitary');
  864. };
  865. /**
  866. * Update the settings to execute the callback or delete the handler.
  867. *
  868. * @param {boolean} autoshowTooltips
  869. * If the user selected the checkbox to autoshow tooltips.
  870. */
  871. this.updateSettings = function(autoshowTooltips) {
  872. var alliancePopupIds = ['diplomacyAllyMemberlist', 'embassy'];
  873. if(autoshowTooltips === true) {
  874. IC.RefreshHandler.add('militaryAdvisor', 'autoshowTooltips', _lf_doAutoshowTooltipsMilitaryAdvisor);
  875. IC.RefreshHandler.add(alliancePopupIds, 'autoshowTooltips', _lf_doAutoshowTooltipsAlliance);
  876. return;
  877. }
  878. IC.RefreshHandler.remove('militaryAdvisor', 'autoshowTooltips');
  879. IC.RefreshHandler.remove(alliancePopupIds, 'autoshowTooltips');
  880. };
  881. };
  882. /**
  883. * Storage for the direct military tooltip functions.
  884. *
  885. * @type {object}
  886. */
  887. var _go_directMilitaryTooltips = new function() {
  888. /**
  889. * Storage for the class ids and their corresponding translations. Each class is a property of the object with the translation stored in it.
  890. *
  891. * @type {object}
  892. */
  893. var _lo_idTranslation = {};
  894. /**
  895. * Fill the id translation object.
  896. */
  897. var _lf_fillIdTranslation = function() {
  898. if(_lo_idTranslation.length === 0)
  899. return;
  900. var la_troops = ['swordsman', 'phalanx', 'archer', 'marksman', 'mortar', 'slinger', 'catapult', 'ram', 'steamgiant', 'bombardier', 'cook', 'medic', 'gyrocopter', 'spearman', 'spartan'];
  901. var la_ships = ['balliasta', 'catapult', 'flamethrower', 'mortar', 'ram', 'steamboat', 'rocketship', 'submarine', 'paddlespeedship', 'balloncarrier', 'tender', 'transport', 'premium_transport'];
  902. var la_resources = IC.Ikariam.resourceNames;
  903. la_resources.push('gold');
  904. la_troops.forEach(function(is_troopName) {
  905. _lo_idTranslation[is_troopName] = IC.Language.$('diverse.name.unit.' + is_troopName);
  906. });
  907. la_ships.forEach(function(is_shipName) {
  908. _lo_idTranslation['ship_' + is_shipName] = IC.Language.$('diverse.name.ship.' + is_shipName.replace('premium_', ''));
  909. });
  910. la_resources.forEach(function(is_resourceName) {
  911. _lo_idTranslation[is_resourceName] = IC.Language.$('diverse.name.resource.' + is_resourceName);
  912. });
  913. };
  914. /**
  915. * Hide the number of ships for the own peaceful missions (trade / transport).
  916. */
  917. var _lf_hideShipNumberOwnPeacefulMissions = function() {
  918. var la_ownEventTableRows = IC.myGM.$$('#js_MilitaryMovementsFleetMovementsTable .military_event_table tr.own');
  919. la_ownEventTableRows.forEach(function(ie_tableRow) {
  920. var le_missionDiv = IC.myGM.$('td:nth-child(1) div.mission_icon', ie_tableRow);
  921. var lb_peacefulMission = le_missionDiv.classList.contains('transport') || le_missionDiv.classList.contains('trade');
  922. if(lb_peacefulMission === true) {
  923. IC.myGM.$('td:nth-child(4) div', ie_tableRow).classList.add('invisible');
  924. }
  925. });
  926. };
  927. /**
  928. * Show the military tooltips directly.
  929. */
  930. var _lf_doShowDirectMilitaryTooltips = function() {
  931. _lf_fillIdTranslation();
  932. _lf_hideShipNumberOwnPeacefulMissions();
  933. IC.myGM.$$('.spyMilitary').forEach(function(ie_movementWrapper) {
  934. ie_movementWrapper.onclick = 'return false;';
  935. });
  936. var le_movementsTable = IC.myGM.$('#js_MilitaryMovementsFleetMovementsTable');
  937. IC.myGM.forEach(_lo_idTranslation, function(is_classId, is_translation) {
  938. IC.myGM.$$('.icon40.' + is_classId, le_movementsTable).forEach(function(ie_detailIcon) {
  939. ie_detailIcon.title = is_translation;
  940. });
  941. });
  942. };
  943. /**
  944. * Update the settings to execute the callback or delete the handler.
  945. *
  946. * @param {boolean} ib_showDirectMilitaryTooltips
  947. * If the user selected the checkbox to show the military tooltips directly.
  948. */
  949. this.updateSettings = function(ib_showDirectMilitaryTooltips) {
  950. if(ib_showDirectMilitaryTooltips === true) {
  951. IC.RefreshHandler.add('militaryAdvisor', 'showDirectMilitaryTooltips', _lf_doShowDirectMilitaryTooltips);
  952. IC.myGM.addStyle(
  953. '#js_MilitaryMovementsFleetMovementsTable .military_event_table .magnify_icon { background-image: none; cursor: default; width: 240px; } \
  954. #js_MilitaryMovementsFleetMovementsTable .military_event_table .magnify_icon .infoTip { display: inline; position: relative; padding: 0px; border: none; top: 0px; } \
  955. #js_MilitaryMovementsFleetMovementsTable .military_event_table .magnify_icon .infoTip h5 { display: none; } \
  956. #js_MilitaryMovementsFleetMovementsTable .military_event_table .icon40 { background-size: 25px 25px; background-color: transparent; padding: 26px 3px 0px 3px; width: 30px; } \
  957. #js_MilitaryMovementsFleetMovementsTable .military_event_table .icon40.resource_icon { background-size: 20px 16px; }',
  958. 'showDirectMilitaryTooltips'
  959. );
  960. return;
  961. }
  962. IC.RefreshHandler.remove('militaryAdvisor', 'showDirectMilitaryTooltips');
  963. IC.myGM.removeStyle('showDirectMilitaryTooltips');
  964. };
  965. };
  966. // Show alliance / military tooltips directly.
  967. IC.Options.addCheckbox('autoshowTooltips', 'diverseOptions', 1, true, IC.Language.$('tooltips.options.autoshow'), { changeCallback: _go_autoshowTooltips.updateSettings });
  968. // Show military tooltips directly.
  969. IC.Options.addCheckbox('showDirectMilitaryTooltips', 'diverseOptions', 1, false, IC.Language.$('tooltips.options.showDirectInMilitaryAdvisor'), { changeCallback: _go_directMilitaryTooltips.updateSettings });
  970. // Add a divider line.
  971. IC.Options.addLine('diverseOptions', 1);
  972. })();
  973. IC.con.logTimeStamp('IkariamEnhancedUI: tooltip functions created');
  974. // Zoom function.
  975. (function() {
  976. /**
  977. * Storage for the zoom functions.
  978. *
  979. * @type {object}
  980. */
  981. var _go_zoomView = new function() {
  982. /**
  983. * Storage for the minimum zoom factor.
  984. *
  985. * @type {int}
  986. */
  987. var _li_minZoom = 55;
  988. /**
  989. * Storage for the maximum zoom factor.
  990. *
  991. * @type {int}
  992. */
  993. var _li_maxZoom = 150;
  994. /**
  995. * Storage for the zoom step size.
  996. *
  997. * @type {int}
  998. */
  999. var _li_zoomStep = 5;
  1000. /**
  1001. * Storage for the actual mousewheel callback.
  1002. *
  1003. * @type {function}
  1004. */
  1005. var _lf_mousewheelCallbackStorage = IC.ika.getController().mouseScrollHandle;
  1006. /**
  1007. * Getter for the minimum zoom factor.
  1008. *
  1009. * @return {int}
  1010. * The minimum zoom factor.
  1011. */
  1012. this.__defineGetter__('minZoom', function() { return _li_minZoom; });
  1013. /**
  1014. * Getter for the maximum zoom factor.
  1015. *
  1016. * @return {int}
  1017. * The maximum zoom factor.
  1018. */
  1019. this.__defineGetter__('maxZoom', function() { return _li_maxZoom; });
  1020. /**
  1021. * Getter for the zoom step size.
  1022. *
  1023. * @return {int}
  1024. * The zoom step size.
  1025. */
  1026. this.__defineGetter__('zoomStep', function() { return _li_zoomStep; });
  1027. /**
  1028. * Initialize the zoom bounds (min and max zoom).
  1029. */
  1030. var _lf_initBounds = function() {
  1031. var li_minZoom = Math.round(IC.ika.worldview_scale_min * 100);
  1032. if(li_minZoom % 5 != 0)
  1033. li_minZoom = li_minZoom + (5 - (li_minZoom % 5));
  1034.  
  1035. _li_minZoom = li_minZoom;
  1036. IC.ika.worldview_scale_min = _li_minZoom / 100;
  1037. IC.ika.worldview_scale_max = _li_maxZoom / 100;
  1038. };
  1039. /**
  1040. * Zoom the world view, as there is no function provided by Ikariam.
  1041. *
  1042. * @param {decimal} in_zoomFactor
  1043. * The zoom factor as decimal number (1 =^= 100%)
  1044. */
  1045. var _lf_zoomWorldView = function(in_zoomFactor) {
  1046. var li_translateXY = (100 - 100 / in_zoomFactor) / 2;
  1047. var ls_heightWidth = (100 / in_zoomFactor) + '% !important';
  1048. var ls_transformString = 'scale(' + in_zoomFactor + ') translate(' + li_translateXY + '%, ' + li_translateXY + '%)';
  1049. IC.myGM.addStyle(
  1050. '#scrollcover { transform: ' + ls_transformString + '; -webkit-transform: ' + ls_transformString + '; height: ' + ls_heightWidth + '; width: ' + ls_heightWidth + '; }',
  1051. 'zoomWorld', true
  1052. );
  1053. var le_map = IC.myGM.$('#map1');
  1054. le_map.style.top = '0px';
  1055. le_map.style.left = '0px';
  1056. };
  1057. /**
  1058. * Rescale the badges and symbols.
  1059. *
  1060. * @param {decimal} in_zoomFactorNumber
  1061. * The zoom factor as decimal number (1 =^= 100%)
  1062. */
  1063. var _lf_scaleChildren = function(in_zoomFactorNumber) {
  1064. var ls_transformString = 'transform: scale(' + 1 / in_zoomFactorNumber + '); -webkit-transform: scale(' + 1 / in_zoomFactorNumber + ');';
  1065. var ls_style = '';
  1066. if(IC.Ikariam.view == 'world') {
  1067. var ls_ownerState = '';
  1068. if(in_zoomFactorNumber < 1)
  1069. ls_ownerState = ', .ownerState';
  1070. ls_style = '.islandTile .wonder, .islandTile .tradegood, .islandTile .cities, .islandTile .piracyInRange' + ls_ownerState + ' { ' + ls_transformString + ' } \
  1071. .islandTile .cities { bottom: 10px !important; }';
  1072. }
  1073. if(IC.Ikariam.view == 'island') {
  1074. var ls_movePiracy = 'transform: translate(0px, -' + (1 - in_zoomFactorNumber) * 20 + 'px) scale(' + 1 / in_zoomFactorNumber + ');';
  1075. ls_style = '.cityLocation .scroll_img, .cityLocationScroll .scroll_img { ' + ls_transformString + ' } \
  1076. .cityLocation .piracyRaid { ' + ls_movePiracy + ' }';
  1077. }
  1078. if(IC.Ikariam.view == 'town')
  1079. ls_style = '.timetofinish { ' + ls_transformString + ' }';
  1080. IC.myGM.addStyle(ls_style, 'scaleChildren', true);
  1081. };
  1082. /**
  1083. * Update the zoom in and zoom out button and the percentage in the middle.
  1084. *
  1085. * @param {int} ii_zoomFactor
  1086. * The zoom factor as percentage.
  1087. */
  1088. var _lf_updateZoomButtons = function(ii_zoomFactor) {
  1089. var le_zoomFactorDiv = IC.myGM.$('#' + IC.myGM.prefix + 'zoomFactor');
  1090. var le_zoomIn = IC.myGM.$('#' + IC.myGM.prefix + 'zoomIn');
  1091. var le_zoomOut = IC.myGM.$('#' + IC.myGM.prefix + 'zoomOut');
  1092. if(!!le_zoomFactorDiv) {
  1093. le_zoomFactorDiv.innerHTML = ii_zoomFactor + '%';
  1094. }
  1095. if(!!le_zoomIn) {
  1096. le_zoomIn.style.visibility = '';
  1097. if(ii_zoomFactor >= _li_maxZoom)
  1098. le_zoomIn.style.visibility = 'hidden';
  1099. }
  1100. if(!!le_zoomOut) {
  1101. le_zoomOut.style.visibility = '';
  1102. if(ii_zoomFactor <= _li_minZoom)
  1103. le_zoomOut.style.visibility = 'hidden';
  1104. }
  1105. };
  1106. /**
  1107. * Calculate the zoom factor as decimal number and execute the zoom function. If it is requestet, call also the rescale function for child elements.
  1108. *
  1109. * @param {int} ii_zoomFactor
  1110. * The zoom factor as percentage.
  1111. */
  1112. var _lf_zoomView = function(ii_zoomFactor) {
  1113. var ln_zoomFactorNumber = ii_zoomFactor / 100.0;
  1114. var li_scale = 0;
  1115. if(IC.Ikariam.view == 'island')
  1116. li_scale = IC.ika.worldview_scale_island;
  1117. if(IC.Ikariam.view == 'town')
  1118. li_scale = IC.ika.worldview_scale_city;
  1119. if(IC.Ikariam.view == 'world') {
  1120. _lf_zoomWorldView(ln_zoomFactorNumber);
  1121. } else {
  1122. var li_stepNumber = Math.round((ln_zoomFactorNumber - li_scale) / .05);
  1123. var le_worldview = IC.myGM.$('#worldview');
  1124. var li_posX = le_worldview.offsetLeft + le_worldview.offsetWidth / 2;
  1125. var li_posY = le_worldview.offsetTop + le_worldview.offsetHeight / 2;
  1126. IC.ika.controller.scaleWorldMap(li_stepNumber, li_posX, li_posY);
  1127. }
  1128. if(IC.Options.getOption('zoom', IC.Ikariam.view + 'ScaleChildren') === true)
  1129. _lf_scaleChildren(ln_zoomFactorNumber);
  1130. };
  1131. /**
  1132. * Ensure that the requested zoom factor is in the bounds and update the view.
  1133. *
  1134. * @param {int} ii_zoomFactor
  1135. * The zoom factor as percentage.
  1136. */
  1137. var _lf_zoom = function(ii_zoomFactor) {
  1138. if(ii_zoomFactor > _li_maxZoom)
  1139. ii_zoomFactor = _li_maxZoom;
  1140. if(ii_zoomFactor < _li_minZoom)
  1141. ii_zoomFactor = _li_minZoom;
  1142. IC.Options.setOption('zoom', IC.Ikariam.view + 'Factor', ii_zoomFactor);
  1143. _lf_updateZoomButtons(ii_zoomFactor);
  1144. _lf_zoomView(ii_zoomFactor);
  1145. };
  1146. /**
  1147. * Zoom one step in.
  1148. */
  1149. var _lf_zoomIn = function() {
  1150. var li_factor = IC.Ikariam.getInt(IC.Options.getOption('zoom', IC.Ikariam.view + 'Factor', 100)) + _li_zoomStep;
  1151. _lf_zoom(li_factor);
  1152. };
  1153. /**
  1154. * Zoom one step out.
  1155. */
  1156. var _lf_zoomOut = function() {
  1157. var li_factor = IC.Options.getOption('zoom', IC.Ikariam.view + 'Factor', 100) - _li_zoomStep;
  1158. _lf_zoom(li_factor);
  1159. };
  1160. /**
  1161. * Add the zoom buttons.
  1162. */
  1163. var _lf_addZoomButtons = function() {
  1164. var le_zoomWrapper = IC.myGM.addElement('div', ge_toolbar, { 'id': 'zoomWrapper' });
  1165. IC.myGM.addElement('div', le_zoomWrapper, {
  1166. 'id': 'zoomIn',
  1167. 'class': 'maximizeImg',
  1168. 'title': IC.Language.$('zoom.zoomIn'),
  1169. 'click': _lf_zoomIn
  1170. });
  1171. IC.myGM.addElement('div', le_zoomWrapper, {
  1172. 'id': 'zoomFactor',
  1173. 'title': IC.Language.$('zoom.factor')
  1174. });
  1175. IC.myGM.addElement('div', le_zoomWrapper, {
  1176. 'id': 'zoomOut',
  1177. 'class': 'minimizeImg',
  1178. 'title': IC.Language.$('zoom.zoomOut'),
  1179. 'click': _lf_zoomOut
  1180. });
  1181. IC.myGM.addStyle(
  1182. '#' + IC.myGM.prefix + 'zoomWrapper { width: 72px; margin: 0px -5px !important; transform: scale(0.75); scale(0.75); -webkit-transform: scale(0.75); } \
  1183. #' + IC.myGM.prefix + 'zoomWrapper > div { display: inline-block; position: relative; } \
  1184. #' + IC.myGM.prefix + 'zoomFactor { top: -4px; width: 35px; text-align: center; }',
  1185. 'zoomButtons'
  1186. );
  1187. };
  1188. /**
  1189. * Set the zoom to 100% if in world view or if it was bigger than 100% and remove the zoom buttons and all styles for the zoom.
  1190. */
  1191. var _lf_resetZoom = function() {
  1192. if((IC.Ikariam.view == 'island' && IC.ika.worldview_scale_island > 1) || (IC.Ikariam.view == 'town' && IC.ika.worldview_scale_city > 1) || IC.Ikariam.view == 'world')
  1193. _lf_zoomView(100);
  1194. IC.ika.worldview_scale_max = 1;
  1195. IC.myGM.removeElement(IC.myGM.$('#' + IC.myGM.prefix + 'zoomWrapper'));
  1196. IC.myGM.removeStyle('zoomButtons');
  1197. IC.myGM.removeStyle('zoomWorld');
  1198. IC.myGM.removeStyle('scaleChildren');
  1199. };
  1200. /**
  1201. * Check, if the key are pressed which are required to zoom with the mouse.
  1202. *
  1203. * @param {object} io_event
  1204. * The "event object" with information about the mouse scroll and pressed keys.
  1205. *
  1206. * @return {boolean}
  1207. * If the correct keys were pressed.
  1208. */
  1209. var _lf_keysOK = function(io_event) {
  1210. var lb_ctrlOK = !!io_event.ctrlKey;
  1211. if(IC.Options.getOption('zoom', 'ctrlAsAccessKey') === false)
  1212. lb_ctrlOK = true;
  1213. var lb_altOK = !!io_event.altKey;
  1214. if(IC.Options.getOption('zoom', 'altAsAccessKey') === false)
  1215. lb_altOK = true;
  1216. var lb_shiftOK = !!io_event.shiftKey;
  1217. if(IC.Options.getOption('zoom', 'shiftAsAccessKey') === false)
  1218. lb_shiftOK = true;
  1219. return lb_ctrlOK && lb_altOK && lb_shiftOK;
  1220. };
  1221. /**
  1222. * Calculate the delta the mousewheel was turned.
  1223. *
  1224. * @param {object} io_event
  1225. * The "event object" with information about the mouse scroll and pressed keys.
  1226. *
  1227. * @return {int}
  1228. * The delta the mousewheel was moved.
  1229. */
  1230. var _lf_calculateDelta = function(io_event) {
  1231. var ri_stepNumber = 0;
  1232.  
  1233. // Get the number of steps to scroll.
  1234. if(io_event.wheelDelta)
  1235. ri_stepNumber = io_event.wheelDelta / 120;
  1236.  
  1237. if (io_event.detail)
  1238. ri_stepNumber = -io_event.detail / 3;
  1239.  
  1240. if (io_event.wheelDeltaY !== undefined)
  1241. ri_stepNumber = io_event.wheelDeltaY / 120;
  1242. // If the number is between -1 and 0, set it to -1.
  1243. if(ri_stepNumber < 0)
  1244. ri_stepNumber = ri_stepNumber > -1 ? -1 : Math.round(ri_stepNumber);
  1245.  
  1246. // If the number is between 0 and 1, set it to 1.
  1247. else
  1248. ri_stepNumber = ri_stepNumber < 1 ? 1 : Math.round(ri_stepNumber);
  1249. return ri_stepNumber;
  1250. };
  1251. /**
  1252. * Handler for mousescroll to zoom.
  1253. *
  1254. * @param {object} io_event
  1255. * The "event object" with information about the mouse scroll and pressed keys.
  1256. *
  1257. * @return false
  1258. * If the prevent default method is not available to prevent the default action.
  1259. */
  1260. var _lf_mouseScroll = function(io_event) {
  1261. if(_lf_keysOK(io_event) === true) {
  1262. // If the scrolling is horizontally return.
  1263. if(io_event.axis !== undefined && io_event.axis === io_event.HORIZONTAL_AXIS)
  1264. return;
  1265. var li_factor = IC.Ikariam.getInt(IC.Options.getOption('zoom', IC.Ikariam.view + 'Factor')) + _li_zoomStep * _lf_calculateDelta(io_event);
  1266. _lf_zoom(li_factor);
  1267. // Prevent the default event.
  1268. if(io_event.preventDefault)
  1269. io_event.preventDefault();
  1270. else
  1271. return false;
  1272. }
  1273. };
  1274. /**
  1275. * Change the mousewheel listener to a new callback.
  1276. *
  1277. * @param {function} if_newCallback
  1278. * The new callback for the mousewheel listener.
  1279. */
  1280. var _lf_changeMouseWheelListener = function(if_newCallback) {
  1281. if(_lf_mousewheelCallbackStorage == if_newCallback)
  1282. return;
  1283. var ls_scrollDivId = '#worldmap';
  1284. if(IC.Ikariam.view == 'world')
  1285. ls_scrollDivId = '#map1';
  1286. if(_lf_mousewheelCallbackStorage == IC.ika.getController().mouseScrollHandle) {
  1287. // Remove the ikariam mouse wheel listener and add the own. (with the use of Ikariam-jQuery)
  1288. IC.win.$(ls_scrollDivId).unbind('mousewheel');
  1289. var scrollDiv = IC.myGM.$(ls_scrollDivId);
  1290. scrollDiv.addEventListener('DOMMouseScroll', if_newCallback, false);
  1291. scrollDiv.addEventListener('mousewheel', if_newCallback, false);
  1292. } else {
  1293. var scrollDiv = IC.myGM.$(ls_scrollDivId);
  1294. scrollDiv.removeEventListener('DOMMouseScroll', _lf_mousewheelCallbackStorage, false);
  1295. scrollDiv.removeEventListener('mousewheel', _lf_mousewheelCallbackStorage, false);
  1296. IC.win.$(ls_scrollDivId).on('mousewheel', if_newCallback);
  1297. }
  1298. _lf_mousewheelCallbackStorage = if_newCallback;
  1299. };
  1300. /**
  1301. * Update the settings to execute the callback or delete the handler.
  1302. *
  1303. * @param {boolean} ib_zoomView
  1304. * If the user selected the checkbox to zoom.
  1305. */
  1306. this.updateSettings = function(ib_zoomView) {
  1307. _lf_initBounds();
  1308. _go_zoomOptions.renewFactorSelects();
  1309. if(ib_zoomView === true) {
  1310. _lf_addZoomButtons();
  1311. _lf_changeMouseWheelListener(_lf_mouseScroll);
  1312. _lf_zoom(IC.Options.getOption('zoom', IC.Ikariam.view + 'Factor'));
  1313. return;
  1314. }
  1315. _lf_resetZoom();
  1316. _lf_changeMouseWheelListener(IC.ika.getController().mouseScrollHandle);
  1317. };
  1318. };
  1319. /**
  1320. * Storage for the option creation functions.
  1321. *
  1322. * @type {object}
  1323. */
  1324. var _go_zoomOptions = new function() {
  1325. /**
  1326. * If the zoom wrapper is already created.
  1327. */
  1328. var _lb_zoomWrapperCreated = false;
  1329. /**
  1330. * Add the select fields for the zoom factors.
  1331. */
  1332. var _lf_addFactorSelects = function(ib_replace) {
  1333. var la_options = [];
  1334. for(var i = _go_zoomView.minZoom; i <= _go_zoomView.maxZoom; i = i + _go_zoomView.zoomStep) {
  1335. la_options.push({ value: i, label: i + '%' });
  1336. }
  1337. IC.Ikariam.viewNames.forEach(function(is_view, ii_index) {
  1338. IC.Options.addSelect(is_view + 'Factor', 'zoom', 'factors', 100, IC.Language.$('zoom.options.factor.' + is_view), la_options, { replace: !!ib_replace });
  1339. });
  1340. };
  1341. /**
  1342. * Add the checkboxes fields for rescaling the badges and icons.
  1343. */
  1344. var _lf_addScaleChildrenCheckboxes = function() {
  1345. IC.Options.addHTML('scaleChildrenDescription', 'zoom', 'scale', { html: '<p>' + IC.Language.$('zoom.options.scaleChildren.label') + '</p>' });
  1346. IC.Ikariam.viewNames.forEach(function(is_view) {
  1347. IC.Options.addCheckbox(is_view + 'ScaleChildren', 'zoom', 'scale', true, IC.Language.$('zoom.options.scaleChildren.' + is_view), {});
  1348. });
  1349. };
  1350. /**
  1351. * Add the checkboxes for the access keys.
  1352. */
  1353. var _lf_addAccessKeyCheckboxes = function() {
  1354. IC.Options.addHTML('accessKeyDescription', 'zoom', 'accessKeys', { html: '<p>' + IC.Language.$('zoom.options.accessKeyLabel') + '</p>' });
  1355. var la_accessKeys = ['ctrl', 'alt', 'shift'];
  1356. la_accessKeys.forEach(function(is_accessKey) {
  1357. var lb_defaultEnabled = (is_accessKey == 'ctrl');
  1358. IC.Options.addCheckbox(is_accessKey + 'AsAccessKey', 'zoom', 'accessKeys', lb_defaultEnabled, IC.Language.$('general.' + is_accessKey), {});
  1359. });
  1360. };
  1361. /**
  1362. * Create the zoom options wrapper and add the option elements.
  1363. */
  1364. this.create = function() {
  1365. _lf_addFactorSelects();
  1366. _lf_addScaleChildrenCheckboxes();
  1367. _lf_addAccessKeyCheckboxes();
  1368. _lb_zoomWrapperCreated = true;
  1369. };
  1370. /**
  1371. * Recreate the select fields for the zoom factor (and keep the old zoom factor).
  1372. */
  1373. this.renewFactorSelects = function() {
  1374. if(_lb_zoomWrapperCreated === false)
  1375. return;
  1376. _lf_addFactorSelects(true);
  1377. };
  1378. };
  1379. IC.Options.addWrapper('zoom', IC.Language.$('zoom.options.wrapperTitle'));
  1380. // Show missing resources in upgrade / building view.
  1381. IC.Options.addCheckbox('view', 'zoom', 'general', true, IC.Language.$('zoom.options.zoomView'), { changeCallback: _go_zoomView.updateSettings });
  1382. // Add the zoom function settings.
  1383. _go_zoomOptions.create();
  1384. })();
  1385. IC.con.logTimeStamp('IkariamEnhancedUI: zoom functions created');
  1386. // Ressource information.
  1387. (function() {
  1388. /**
  1389. * Storage for the style functions for the capacity bar and the direct income.
  1390. *
  1391. * @type {object}
  1392. */
  1393. var _go_styleFunctions = new function() {
  1394. /**
  1395. * Get the style for the #js_GlobalMenu_ elements.
  1396. *
  1397. * @param {string} is_incomeStyle
  1398. * How the income is styled.
  1399. *
  1400. * @return {string}
  1401. * The style string.
  1402. */
  1403. var _lf_getGlobalMenuStyle = function(is_incomeStyle) {
  1404. if(is_incomeStyle != 'alignLeft')
  1405. return '#js_GlobalMenu_wood, #js_GlobalMenu_wine, #js_GlobalMenu_marble, #js_GlobalMenu_crystal, #js_GlobalMenu_sulfur { padding-right: 4px; } ';
  1406. return '';
  1407. };
  1408. /**
  1409. * Gets the style for the separation of the resource values.
  1410. *
  1411. * @param {string} is_incomeStyle
  1412. * How the income is styled.
  1413. *
  1414. * @return {string}
  1415. * The style string.
  1416. */
  1417. var _lf_getSeparationStyle = function(is_incomeStyle) {
  1418. if(is_incomeStyle == 'withSeparation')
  1419. return '#resources_wood, #resources_wine, #resources_marble, #resources_glass { border-right: 1px dotted #542C0F; } ';
  1420. return '';
  1421. };
  1422. /**
  1423. * Get styles which are independent of the activation of the cpacity bar or direct income.
  1424. *
  1425. * @param {string} is_incomeStyle
  1426. * How the income is styled.
  1427. *
  1428. * @return {string}
  1429. * The style string.
  1430. */
  1431. var _lf_getGeneralStyles = function(is_incomeStyle) {
  1432. var ls_globalMenuStyle = _lf_getGlobalMenuStyle(is_incomeStyle);
  1433. var ls_separationStyle = _lf_getSeparationStyle(is_incomeStyle);
  1434. return ls_globalMenuStyle + ls_separationStyle;
  1435. };
  1436. /**
  1437. * Get the style for the capacity bar "wrapper".
  1438. *
  1439. * @param {string} is_capacityBarOrientation
  1440. * The orientation of the capacity bar.
  1441. * @param {string} is_incomeStyle
  1442. * How the income is styled.
  1443. *
  1444. * @return {string}
  1445. * The style string.
  1446. */
  1447. var _lf_getCapacityBarStyle = function(is_capacityBarOrientation, is_incomeStyle) {
  1448. var ls_height = 'height: 4px; ';
  1449. var ls_width = 'width: 79px;';
  1450. var ls_right = 'right: 4px; ';
  1451. var ls_marginLeft = '';
  1452. if(is_capacityBarOrientation == 'horizontal')
  1453. ls_width = 'width: 50px; ';
  1454. if(is_capacityBarOrientation == 'vertical') {
  1455. ls_height = 'height: 21px; ';
  1456. ls_width = 'width: 4px; ';
  1457. ls_right = '';
  1458. if(is_incomeStyle == 'alignLeft')
  1459. ls_marginLeft = 'margin-left: -7px; ';
  1460. }
  1461. return '.' + IC.myGM.prefix + 'capacityInformation { position: absolute; bottom: 4px; ' + ls_height + ls_width + ls_right + ls_marginLeft + '} ';
  1462. };
  1463. /**
  1464. * Get the style for the capacity bar with a border.
  1465. *
  1466. * @param {string} is_capacityBarOrientation
  1467. * The orientation of the capacity bar.
  1468. *
  1469. * @return {string}
  1470. * The style string.
  1471. */
  1472. var _lf_getCapacityBarWithBorderStyle = function(is_capacityBarOrientation) {
  1473. var ls_height = 'height: 3px; ';
  1474. var ls_width = 'width: 78px; ';
  1475. var ls_right = 'right: 3px; ';
  1476. if(is_capacityBarOrientation == 'horizontal')
  1477. ls_width = 'width: 50px; ';
  1478. if(is_capacityBarOrientation == 'vertical') {
  1479. ls_height = 'height: 20px; ';
  1480. ls_width = 'width: 3px; ';
  1481. ls_right = '';
  1482. }
  1483. return '.' + IC.myGM.prefix + 'capacityInformation.' + IC.myGM.prefix + 'border { border: 1px inset #906646; bottom: 3px; ' + ls_height + ls_width + ls_right + '} ';
  1484. };
  1485. /**
  1486. * Get the style for the capacity bar.
  1487. *
  1488. * @param {string} is_capacityBarOrientation
  1489. * The orientation of the capacity bar.
  1490. * @param {string} is_incomeStyle
  1491. * How the income is styled.
  1492. *
  1493. * @return {string}
  1494. * The style string.
  1495. */
  1496. var _lf_getCapacityStyle = function(is_capacityBarOrientation, is_incomeStyle) {
  1497. var ls_prefix = IC.myGM.prefix;
  1498. var ls_barStyle = '.' + ls_prefix + 'bar { height: 100%; width: 100%; bottom: 0px; position: absolute; } \
  1499. .' + ls_prefix + 'bar.' + ls_prefix + 'red { background-color: #AA0000; } \
  1500. .' + ls_prefix + 'bar.' + ls_prefix + 'yellow { background-color: #FFD700; } \
  1501. .' + ls_prefix + 'bar.' + ls_prefix + 'green { background-color: #669900; }';
  1502. var ls_capacityStyle = _lf_getCapacityBarStyle(is_capacityBarOrientation, is_incomeStyle);
  1503. var ls_capacityBorderStyle = _lf_getCapacityBarWithBorderStyle(is_capacityBarOrientation);
  1504. return ls_barStyle + ls_capacityStyle + ls_capacityBorderStyle;
  1505. };
  1506. /**
  1507. * Get the style for the direct hourly income in the town view.
  1508. *
  1509. * @param {boolean} ib_capacityBarActive
  1510. * If the capacity bar is shown.
  1511. * @param {string} is_capacityBarOrientation
  1512. * The orientation of the capacity bar.
  1513. * @param {string} is_incomeStyle
  1514. * How the income is styled.
  1515. *
  1516. * @return {string}
  1517. * The style string.
  1518. */
  1519. var _lf_getHourlyIncomeStyle = function(ib_capacityBarActive, is_capacityBarOrientation, is_incomeStyle) {
  1520. var ls_display = 'display: block; ';
  1521. var ls_fontSize = 'font-size: 11px; ';
  1522. var ls_paddingRight = 'padding-right: 4px; ';
  1523. if(ib_capacityBarActive === true && is_capacityBarOrientation !== 'horizontalFull')
  1524. ls_fontSize = 'font-size: 9px; ';
  1525. if(is_incomeStyle == 'alignLeft')
  1526. ls_paddingRight = '';
  1527. return '.' + IC.myGM.prefix + 'hourlyIncomeResource { ' + ls_display + ls_fontSize + ls_paddingRight + '} ';
  1528. };
  1529. /**
  1530. * Get some resource styles which are only set if the capacity bar is active.
  1531. *
  1532. * @param {boolean} ib_directIncomeActive
  1533. * If the direct income is shown.
  1534. * @param {string} is_capacityBarOrientation
  1535. * The orientation of the capacity bar.
  1536. * @param {string} is_incomeStyle
  1537. * How the income is styled.
  1538. *
  1539. * @return {string}
  1540. * The style string.
  1541. */
  1542. var _lf_getResourceStyleCapacityActive = function(ib_directIncomeActive, is_capacityBarOrientation, is_incomeStyle) {
  1543. var ls_height = '';
  1544. var ls_top = '';
  1545. var ls_paddingLeft = '';
  1546. var ls_fontSize = '';
  1547. if(is_capacityBarOrientation == 'horizontalFull') {
  1548. ls_height = 'height: 32px !important; ';
  1549. ls_top = 'top: -2px !important; ';
  1550. }
  1551. if(is_capacityBarOrientation == 'vertical' && is_incomeStyle == 'alignLeft')
  1552. ls_paddingLeft = 'padding-left: 38px !important; ';
  1553. if(is_capacityBarOrientation == 'vertical' || (ib_directIncomeActive === true && is_capacityBarOrientation != 'horizontalFull'))
  1554. ls_fontSize = 'font-size: 11px; ';
  1555. return ls_height + ls_top + ls_paddingLeft + ls_fontSize;
  1556. };
  1557. /**
  1558. * Get the line height for the sored resources.
  1559. *
  1560. * @param {boolean} ib_capacityBarActive
  1561. * If the capacity bar is shown.
  1562. * @param {boolean} ib_directIncomeActive
  1563. * If the direct income is shown.
  1564. * @param {string} is_capacityBarOrientation
  1565. * The orientation of the capacity bar.
  1566. *
  1567. * @return {string}
  1568. * The style string.
  1569. */
  1570. var _lf_getResourceStyleLineHeigth = function(ib_capacityBarActive, ib_directIncomeActive, is_capacityBarOrientation) {
  1571. if(ib_directIncomeActive === true) {
  1572. if(ib_capacityBarActive === true && is_capacityBarOrientation == 'horizontal')
  1573. return 'line-height: 9px !important; ';
  1574. return 'line-height: 11px !important; ';
  1575. }
  1576. if(is_capacityBarOrientation == 'horizontal')
  1577. return 'line-height: 12px !important; ';
  1578. if(is_capacityBarOrientation == 'vertical')
  1579. return 'line-height: 24px !important; ';
  1580. return '';
  1581. };
  1582. /**
  1583. * Get the style for the resource fields.
  1584. *
  1585. * @param {boolean} ib_capacityBarActive
  1586. * If the capacity bar is shown.
  1587. * @param {boolean} ib_directIncomeActive
  1588. * If the direct income is shown.
  1589. * @param {string} is_capacityBarOrientation
  1590. * The orientation of the capacity bar.
  1591. * @param {string} is_incomeStyle
  1592. * How the income is styled.
  1593. *
  1594. * @return {string}
  1595. * The style string.
  1596. */
  1597. var _lf_getResourceStyle = function(ib_capacityBarActive, ib_directIncomeActive, is_capacityBarOrientation, is_incomeStyle) {
  1598. var ls_align = 'text-align: right; ';
  1599. var ls_capacityActive = '';
  1600. var ls_lineHeight = _lf_getResourceStyleLineHeigth(ib_capacityBarActive, ib_directIncomeActive, is_capacityBarOrientation);
  1601. if(is_incomeStyle == 'alignLeft')
  1602. ls_align = '';
  1603. if(ib_capacityBarActive === true)
  1604. ls_capacityActive = _lf_getResourceStyleCapacityActive(ib_directIncomeActive, is_capacityBarOrientation, is_incomeStyle);
  1605. return '#resources_wood, #resources_wine, #resources_marble, #resources_glass, #resources_sulfur { ' + ls_align + ls_lineHeight + ls_capacityActive + ' } ';
  1606. };
  1607. /**
  1608. * Set the styles for the direct income and the capacity bar.
  1609. */
  1610. this.setStyles = function() {
  1611. var lb_capacityBarActive = IC.Options.getOption('resourceInformation', 'showCapacityBar');
  1612. var lb_directIncomeActive = IC.Options.getOption('resourceInformation', 'showDirectIncome');
  1613. // If not both of the checkboxes have been defined yet, do nothing!
  1614. if(lb_capacityBarActive === null || lb_directIncomeActive === null)
  1615. return;
  1616. if(lb_capacityBarActive === false && lb_directIncomeActive === false) {
  1617. IC.myGM.removeStyle('resourceInformation');
  1618. return;
  1619. }
  1620. var ls_capacityBarOrientation = IC.Options.getOption('resourceInformation', 'capacityBarOrientation');
  1621. var ls_incomeStyle = IC.Options.getOption('resourceInformation', 'incomeStyle');
  1622. var ls_incomeStyleString = _lf_getGeneralStyles(ls_incomeStyle)
  1623. + _lf_getResourceStyle(lb_capacityBarActive, lb_directIncomeActive, ls_capacityBarOrientation, ls_incomeStyle);
  1624. if(lb_capacityBarActive === true)
  1625. ls_incomeStyleString += _lf_getCapacityStyle(ls_capacityBarOrientation, ls_incomeStyle);
  1626. if(lb_directIncomeActive === true)
  1627. ls_incomeStyleString += _lf_getHourlyIncomeStyle(lb_capacityBarActive, ls_capacityBarOrientation, ls_incomeStyle);
  1628. IC.myGM.addStyle(ls_incomeStyleString, 'resourceInformation', true);
  1629. };
  1630. };
  1631. /**
  1632. * Storage for the functions for the capacity bar.
  1633. *
  1634. * @type {object}
  1635. */
  1636. var _go_capacityInformation = new function() {
  1637. /**
  1638. * Update the capacity information bars.
  1639. */
  1640. var _lf_updateFields = function() {
  1641. if(IC.ika.model.isOwnCity === false)
  1642. return;
  1643. var la_capacityInformation = [];
  1644. var la_resourceIdentifiers = ['resource', 1, 2, 3, 4];
  1645. la_resourceIdentifiers.forEach(function(im_identifier, ii_index) {
  1646. la_capacityInformation.push({
  1647. warehouse: IC.Ikariam.getInt(IC.ika.getModel().maxResources[im_identifier]),
  1648. branchOffice: IC.Ikariam.getInt(IC.ika.getModel().branchOfficeResources[im_identifier]),
  1649. current: IC.Ikariam.getInt(IC.ika.getModel().currentResources[im_identifier])
  1650. });
  1651. });
  1652. var ls_prefix = '#' + IC.myGM.prefix;
  1653. var ls_styleToChange = 'width';
  1654. if(IC.Options.getOption('resourceInformation', 'capacityBarOrientation') == 'vertical')
  1655. ls_styleToChange = 'height';
  1656. la_capacityInformation.forEach(function(io_capacity, ii_index) {
  1657. var ls_resource = IC.Ikariam.resourceNames[ii_index];
  1658. var li_warehousePercentage = 100;
  1659. var li_resourcePercentage = io_capacity.current / io_capacity.warehouse * 100;
  1660. if(IC.Options.getOption('resourceInformation', 'capacityBarShowBranchOfficeResources') === true) {
  1661. var li_maximumCapacity = io_capacity.warehouse + io_capacity.branchOffice;
  1662. li_warehousePercentage = io_capacity.warehouse / li_maximumCapacity * 100;
  1663. li_resourcePercentage = io_capacity.current / li_maximumCapacity * 100;
  1664. }
  1665. IC.myGM.$(ls_prefix + 'maxCapacity' + ls_resource).style[ls_styleToChange] = '100%';
  1666. IC.myGM.$(ls_prefix + 'warehouseCapacity' + ls_resource).style[ls_styleToChange] = li_warehousePercentage + '%';
  1667. IC.myGM.$(ls_prefix + 'currentResource' + ls_resource).style[ls_styleToChange] = li_resourcePercentage + '%';
  1668. });
  1669. };
  1670. /**
  1671. * Add the capacity information bars.
  1672. */
  1673. var _lf_addFields = function() {
  1674. var la_classes = ['capacityInformation'];
  1675. if(IC.Options.getOption('resourceInformation', 'capacityBarHasBorder') === true)
  1676. la_classes.push('border');
  1677. IC.Ikariam.resourceNames.forEach(function(is_resource) {
  1678. var le_wrapper = IC.myGM.addElement('div', IC.myGM.$('#resources_' + is_resource), { 'id': 'capacityInfo' + is_resource, 'classes': la_classes }, true);
  1679. IC.myGM.addElement('div', le_wrapper, { 'id': 'maxCapacity' + is_resource, 'classes': ['bar', 'yellow'] }, true);
  1680. IC.myGM.addElement('div', le_wrapper, { 'id': 'warehouseCapacity' + is_resource, 'classes': ['bar', 'green'] }, true);
  1681. IC.myGM.addElement('div', le_wrapper, { 'id': 'currentResource' + is_resource, 'classes': ['bar', 'red'] }, true);
  1682. });
  1683. _lf_updateFields();
  1684. };
  1685. /**
  1686. * Remove the capacity information bars.
  1687. */
  1688. var _lf_removeFields = function() {
  1689. IC.myGM.removeElement(IC.myGM.$$('.' + IC.myGM.prefix + 'capacityInformation'));
  1690. };
  1691. /**
  1692. * Update the settings to execute the callback or delete the handler.
  1693. *
  1694. * @param {boolean} ib_showCapacityBar
  1695. * If the user selected the checkbox to show the capacity information.
  1696. */
  1697. this.updateSettings = function(ib_showCapacityBar) {
  1698. _go_styleFunctions.setStyles();
  1699. if(ib_showCapacityBar === true) {
  1700. _lf_addFields();
  1701. IC.Observer.add('updateCapacityBar', IC.myGM.$('#cityResources'), { childList: true, subtree: true }, _lf_updateFields, _lf_updateFields);
  1702. return;
  1703. }
  1704. IC.Observer.remove('updateCapacityBar');
  1705. _lf_removeFields();
  1706. };
  1707. };
  1708. /**
  1709. * Storage for the functions for the direct income.
  1710. *
  1711. * @type {object}
  1712. */
  1713. var _go_directIncome = new function() {
  1714. /**
  1715. * Storage for the tradegood of the last town selected.
  1716. *
  1717. * @type {int}
  1718. */
  1719. var _li_lastTradegood = null;
  1720. /**
  1721. * Delete the data of the tradegood of the last town selected.
  1722. *
  1723. * @param {string} is_hourlyPrefix
  1724. * The prefix for the hourly income wrapper selector.
  1725. * @param {string} is_dailyPrefix
  1726. * The prefix for the daily income wrapper selector.
  1727. */
  1728. var _lf_deleteLastTradegoodData = function(is_hourlyPrefix, is_dailyPrefix) {
  1729. IC.myGM.$(is_hourlyPrefix + IC.Ikariam.resourceNames[_li_lastTradegood]).innerHTML = '';
  1730. IC.myGM.$(is_dailyPrefix + IC.Ikariam.resourceNames[_li_lastTradegood]).innerHTML = '';
  1731. if(_li_lastTradegood !== 1) {
  1732. IC.myGM.$(is_hourlyPrefix + IC.Ikariam.resourceNames[_li_lastTradegood]).classList.add('invisible');
  1733. IC.myGM.$(is_dailyPrefix + 'Wrapper' + IC.Ikariam.resourceNames[_li_lastTradegood]).classList.add('invisible');
  1734. }
  1735. };
  1736. /**
  1737. * Update the direct icome fields.
  1738. *
  1739. * @param {boolean} ib_firstRun
  1740. * If this is the first run after adding the fields.
  1741. */
  1742. var _lf_updateFields = function(ib_firstRun) {
  1743. if(IC.ika.model.isOwnCity === false)
  1744. return;
  1745. var ls_hourlyPrefix = '#' + IC.myGM.prefix + 'hourlyIncomeResource';
  1746. var ls_dailyPrefix = '#' + IC.myGM.prefix + 'dailyIncomeResource';
  1747. if(_li_lastTradegood !== null)
  1748. _lf_deleteLastTradegoodData(ls_hourlyPrefix, ls_dailyPrefix);
  1749. var li_producedTradegood = IC.Ikariam.getInt(IC.ika.getModel().producedTradegood);
  1750. var li_tradegoodProduction = IC.ika.getModel().tradegoodProduction * 3600 + 0.001;
  1751. var li_woodProduction = IC.ika.getModel().resourceProduction * 3600 + 0.001;
  1752. var li_wineSpending = IC.ika.getModel().wineSpendings;
  1753. var li_producesWine = IC.ika.getModel().cityProducesWine;
  1754. var ls_tradegoodName = IC.Ikariam.resourceNames[li_producedTradegood];
  1755. IC.myGM.$(ls_hourlyPrefix + IC.Ikariam.resourceNames[0]).innerHTML = IC.Ikariam.formatToIkaNumber(Math.floor(li_woodProduction), true, true);
  1756. IC.myGM.$(ls_dailyPrefix + IC.Ikariam.resourceNames[0]).innerHTML = IC.Ikariam.formatToIkaNumber(Math.floor(li_woodProduction * 24), false);
  1757. IC.myGM.$(ls_hourlyPrefix + IC.Ikariam.resourceNames[1]).innerHTML = IC.Ikariam.formatToIkaNumber(Math.floor(-1 * li_wineSpending), true, true);
  1758. IC.myGM.$(ls_dailyPrefix + IC.Ikariam.resourceNames[1]).innerHTML = IC.Ikariam.formatToIkaNumber(Math.floor(-1 * li_wineSpending * 24), false);
  1759. IC.myGM.$(ls_dailyPrefix + 'Label' + IC.Ikariam.resourceNames[1]).innerHTML = IC.Language.$('resourceInformation.dailyExpenses', [IC.Language.$('diverse.name.resource.' + IC.Ikariam.resourceNames[1])]);
  1760. if(li_producesWine === true)
  1761. li_tradegoodProduction = li_tradegoodProduction - li_wineSpending;
  1762. if(li_tradegoodProduction >= 0)
  1763. IC.myGM.$(ls_dailyPrefix + 'Label' + ls_tradegoodName).innerHTML = IC.Language.$('resourceInformation.dailyProduction', [IC.Language.$('diverse.name.resource.' + ls_tradegoodName)]);
  1764. else
  1765. IC.myGM.$(ls_dailyPrefix + 'Label' + ls_tradegoodName).innerHTML = IC.Language.$('resourceInformation.dailyExpenses', [IC.Language.$('diverse.name.resource.' + ls_tradegoodName)]);
  1766. IC.myGM.$(ls_hourlyPrefix + ls_tradegoodName).innerHTML = IC.Ikariam.formatToIkaNumber(Math.floor(li_tradegoodProduction), true, true);
  1767. IC.myGM.$(ls_dailyPrefix + ls_tradegoodName).innerHTML = IC.Ikariam.formatToIkaNumber(Math.floor(li_tradegoodProduction * 24), false);
  1768. IC.myGM.$(ls_hourlyPrefix + ls_tradegoodName).classList.remove('invisible');
  1769. IC.myGM.$(ls_dailyPrefix + 'Wrapper' + ls_tradegoodName).classList.remove('invisible');
  1770. _li_lastTradegood = li_producedTradegood;
  1771. };
  1772. /**
  1773. * Add the direct income fields.
  1774. */
  1775. var _lf_addFields = function() {
  1776. if(!IC.myGM.$('js_GlobalMenu_production_container_wood') === true) {
  1777. var le_woodProductionContainer = IC.myGM.$('#js_GlobalMenu_resourceProduction').parentNode;
  1778. le_woodProductionContainer.id = 'js_GlobalMenu_production_container_wood';
  1779. }
  1780. IC.Ikariam.resourceNames.forEach(function(is_resource, ii_index) {
  1781. var ls_resourceParent = is_resource === 'glass' ? 'crystal' : is_resource;
  1782. var la_hourlyClasses = [IC.myGM.prefix + 'hourlyIncomeResource'];
  1783. var la_dailyClasses = ['altTooltip', IC.myGM.prefix + 'dailyIncomeResourceWrapper'];
  1784.  
  1785. if(ii_index >= 2) {
  1786. la_hourlyClasses.push('invisible');
  1787. la_dailyClasses.push('invisible');
  1788. }
  1789. IC.myGM.addElement('span', IC.myGM.$('#resources_' + is_resource), { 'id': 'hourlyIncomeResource' + is_resource, 'classes': la_hourlyClasses });
  1790. var le_dailyIncomeParent = IC.myGM.$('#js_GlobalMenu_' + ls_resourceParent + '_tooltip tbody');
  1791. var le_dailyIncomeInsertBefore = IC.myGM.$('#js_GlobalMenu_production_container_' + ls_resourceParent + ' + tr');
  1792. var le_dailyIncomeWrapper = IC.myGM.addElement('tr', le_dailyIncomeParent, {
  1793. 'id': 'dailyIncomeResourceWrapper' + is_resource,
  1794. 'classes': la_dailyClasses,
  1795. }, null, le_dailyIncomeInsertBefore);
  1796. IC.myGM.addElement('td', le_dailyIncomeWrapper, {
  1797. 'id': 'dailyIncomeResourceLabel' + is_resource,
  1798. 'class': 'smallFont',
  1799. 'innerHTML': IC.Language.$('resourceInformation.dailyProduction', [IC.Language.$('diverse.name.resource.' + is_resource)])
  1800. });
  1801. IC.myGM.addElement('td', le_dailyIncomeWrapper, {
  1802. 'id': 'dailyIncomeResource' + is_resource,
  1803. 'class': 'rightText'
  1804. });
  1805. });
  1806. _lf_updateFields(true);
  1807. };
  1808. /**
  1809. * Remove the direct income fields.
  1810. */
  1811. var _lf_removeFields = function() {
  1812. IC.myGM.removeElement(IC.myGM.$$('.' + IC.myGM.prefix + 'hourlyIncomeResource' + ', .' + IC.myGM.prefix + 'dailyIncomeResourceWrapper'));
  1813. };
  1814. /**
  1815. * Update the settings to execute the callback or delete the handler.
  1816. *
  1817. * @param {boolean} ib_showDirectIncome
  1818. * If the user selected the checkbox to show the income directly in town view.
  1819. */
  1820. this.updateSettings = function(ib_showDirectIncome) {
  1821. _go_styleFunctions.setStyles();
  1822. if(ib_showDirectIncome === true) {
  1823. _lf_addFields();
  1824. IC.RefreshHandler.add('*', 'directIncome', _lf_updateFields);
  1825. return;
  1826. }
  1827. IC.RefreshHandler.remove('*', 'directIncome');
  1828. _lf_removeFields();
  1829. };
  1830. };
  1831. /**
  1832. * Storage for the functions for the resource quicklinks enhancements.
  1833. *
  1834. * @type {object}
  1835. */
  1836. var _go_resourceQuicklinkEnhancements = new function() {
  1837. /**
  1838. * Open the town hall of the selected town.
  1839. */
  1840. var _lf_openTownHall = function() {
  1841. var ls_selectedCity = IC.ika.getModel().relatedCityData.selectedCity;
  1842. var ls_cityId = IC.ika.getModel().relatedCityData[ls_selectedCity].id;
  1843. if(IC.Ikariam.view == 'town') {
  1844. IC.win.ajaxHandlerCall('?view=townHall&cityId=' + ls_cityId + '&position=0');
  1845. return;
  1846. }
  1847. IC.win.ajaxHandlerCall('?view=city&dialog=townHall&cityId=' + ls_cityId + '&position=0');
  1848. };
  1849. /**
  1850. * Update the css to hover only the resources which are clickable.
  1851. */
  1852. var _lf_updateCSS = function() {
  1853. var ls_activeResource = IC.Ikariam.resourceNames[IC.ika.getModel().producedTradegood];
  1854. IC.myGM.addStyle(
  1855. '#resources_population:hover, #resources_wood:hover, #resources_' + ls_activeResource + ':hover { text-shadow: 2px 2px 2px #666; cursor: pointer; color: #333; }',
  1856. 'resourceQuicklinkEnhancements', true
  1857. );
  1858. };
  1859. /**
  1860. * Update the settings to execute the callback or delete the handler.
  1861. *
  1862. * @param {boolean} ib_enhanceResourceQuicklinks
  1863. * If the user selected the checkbox to enhance the resource quicklinks.
  1864. */
  1865. this.updateSettings = function(ib_enhanceResourceQuicklinks) {
  1866. if(ib_enhanceResourceQuicklinks === true) {
  1867. IC.myGM.$('#resources_population').addEventListener('click', _lf_openTownHall, true);
  1868. IC.RefreshHandler.add('*', 'resourceQuicklinkEnhancements', _lf_updateCSS);
  1869. return;
  1870. }
  1871. IC.RefreshHandler.remove('*', 'resourceQuicklinkEnhancements');
  1872. IC.myGM.$('#resources_population').removeEventListener('click', _lf_openTownHall, true);
  1873. IC.myGM.removeStyle('resourceQuicklinkEnhancements');
  1874. };
  1875. };
  1876. IC.Options.addWrapper('resourceInformation', IC.Language.$('resourceInformation.options.wrapperTitle'));
  1877. // Option to show the income directly in town view.
  1878. IC.Options.addCheckbox('showDirectIncome', 'resourceInformation', 1, true, IC.Language.$('resourceInformation.options.directIncome.show'), { changeCallback: _go_directIncome.updateSettings });
  1879. // Option to enhance the resource quicklinks and add one to population.
  1880. IC.Options.addCheckbox('resourceQuicklinkEnhancements', 'resourceInformation', 1, true, IC.Language.$('resourceInformation.options.resourceQuicklinkEnhancements'), { changeCallback: _go_resourceQuicklinkEnhancements.updateSettings });
  1881. // Option to show the capacity information.
  1882. IC.Options.addCheckbox('showCapacityBar', 'resourceInformation', 2, true, IC.Language.$('resourceInformation.options.capacityBar.show'), { changeCallback: _go_capacityInformation.updateSettings });
  1883. // Option to show the capacity bar with border.
  1884. IC.Options.addCheckbox('capacityBarHasBorder', 'resourceInformation', 2, true, IC.Language.$('resourceInformation.options.capacityBar.hasBorder'), {});
  1885. // Option to show also branch office ressources.
  1886. IC.Options.addCheckbox('capacityBarShowBranchOfficeResources', 'resourceInformation', 2, true, IC.Language.$('resourceInformation.options.capacityBar.showBranchOfficeResources'), {});
  1887. // Style of the resources in warehouse / daily income.
  1888. IC.Options.addSelect('incomeStyle', 'resourceInformation', 3, 'alignRight', IC.Language.$('resourceInformation.options.directIncome.style.label'), [
  1889. { value: 'alignRight', label: IC.Language.$('resourceInformation.options.directIncome.style.alignRight') },
  1890. { value: 'alignLeft', label: IC.Language.$('resourceInformation.options.directIncome.style.alignLeft') },
  1891. { value: 'withSeparation', label: IC.Language.$('resourceInformation.options.directIncome.style.withSeparation') }
  1892. ], {});
  1893. // Style of the capacity bar.
  1894. IC.Options.addSelect('capacityBarOrientation', 'resourceInformation', 3, 'vertical', IC.Language.$('resourceInformation.options.capacityBar.orientation.label'), [
  1895. { value: 'vertical', label: IC.Language.$('resourceInformation.options.capacityBar.orientation.vertical') },
  1896. { value: 'horizontal', label: IC.Language.$('resourceInformation.options.capacityBar.orientation.horizontal') },
  1897. { value: 'horizontalFull', label: IC.Language.$('resourceInformation.options.capacityBar.orientation.horizontalFull') }
  1898. ], {});
  1899. })();
  1900. IC.con.logTimeStamp('IkariamEnhancedUI: resource information functions created');
  1901. // Member information in highscore view.
  1902. (function() {
  1903. /**
  1904. * Storage for the member information functions.
  1905. *
  1906. * @type {object}
  1907. */
  1908. var _go_memberInformation = new function() {
  1909. /**
  1910. * Storage for the member data.
  1911. *
  1912. * @type {object}
  1913. */
  1914. var _lo_data = null;
  1915. /**
  1916. * Key for the storage of the member information.
  1917. *
  1918. * @type {string}
  1919. */
  1920. var _ls_dataKey = '';
  1921. /**
  1922. * Key for the storage of the last reset date.
  1923. *
  1924. * @type {string}
  1925. */
  1926. var _ls_timeKey = '';
  1927. /**
  1928. * Show the data.
  1929. */
  1930. var _lf_clickShow = function() {
  1931. IC.myGM.setValue('memberInfo_infoLinkClicked', true).then(function() {
  1932. IC.myGM.$('#tab_highscore input[name="searchUser"]').value = '';
  1933. IC.myGM.$('#searchOnlyFriends').checked = false;
  1934. IC.myGM.$('#searchOnlyAllies').checked = true;
  1935. IC.myGM.$('#tab_highscore input[type="submit"]').click();
  1936. });
  1937. };
  1938. /**
  1939. * Reset the stored data.
  1940. */
  1941. var _lf_clickReset = function() {
  1942. IC.myGM.setValue(_ls_dataKey, _lo_data).then(function() {
  1943. return IC.myGM.setValue(_ls_timeKey, (new Date).getTime());
  1944. }).then(function() {
  1945. _lf_clickShow();
  1946. });
  1947. };
  1948. /**
  1949. * Add the button to show the data.
  1950. */
  1951. var _lf_addShowButton = function() {
  1952. var le_button = IC.myGM.addButton(IC.myGM.$('#tab_highscore .centerButton'), IC.Language.$('highscore.memberInformation.show'), _lf_clickShow, true);
  1953. le_button.id = IC.myGM.prefix + 'showInfo';
  1954. };
  1955. /**
  1956. * Add the button to reset the stored data.
  1957. */
  1958. var _lf_addResetButton = function() {
  1959. var le_button = IC.myGM.addButton(IC.myGM.$('#tab_highscore .content p'), IC.Language.$('highscore.memberInformation.reset'), _lf_clickReset, true);
  1960. le_button.id = IC.myGM.prefix + 'resetInfo';
  1961. };
  1962. /**
  1963. * Get the own data and show the differences to the last stored data.
  1964. *
  1965. * @param {object} io_oldMemberInfo
  1966. * The last stored data.
  1967. *
  1968. * @return {object}
  1969. * The own data.
  1970. */
  1971. var _lf_getOwnDataShowDifference = function(io_oldMemberInfo) {
  1972. var le_ownRow = IC.myGM.$('table.highscore tr.own');
  1973. var ro_ownData = {
  1974. 'place': IC.Ikariam.getInt(IC.myGM.$('.place', le_ownRow).innerHTML),
  1975. 'score': IC.Ikariam.getInt(IC.myGM.$('.score', le_ownRow).innerHTML)
  1976. };
  1977. var ls_placeDifference = '-';
  1978. var ls_scoreDifference = '-';
  1979. if(!!io_oldMemberInfo === true && !!io_oldMemberInfo['own'] === true) {
  1980. ls_placeDifference = IC.Ikariam.formatToIkaNumber(io_oldMemberInfo['own']['place'] - ro_ownData['place'], true, true);
  1981. ls_scoreDifference = IC.Ikariam.formatToIkaNumber(ro_ownData['score'] - io_oldMemberInfo['own']['score'], true, true);
  1982. }
  1983. IC.myGM.addElement('span', IC.myGM.$('.place', le_ownRow), { 'innerHTML': ls_placeDifference });
  1984. IC.myGM.addElement('span', IC.myGM.$('.score', le_ownRow), { 'innerHTML': ls_scoreDifference });
  1985. return ro_ownData;
  1986. };
  1987. /**
  1988. * Get the data and show the differences to the last stored data.
  1989. *
  1990. * @return {Promise}
  1991. * A Promise which resolves to the member data.
  1992. */
  1993. var _lf_getDataShowDifference = async function() {
  1994. var ro_memberInfo = {};
  1995. var lo_oldMemberInfo = await IC.myGM.getValue(_ls_dataKey, null);
  1996. var la_allyMemberRows = IC.myGM.$$('table.highscore tr.ownally');
  1997. la_allyMemberRows.forEach(function(ie_allyMemberRow) {
  1998. var ls_actionLink = IC.myGM.$('.action a', ie_allyMemberRow).href;
  1999. var ls_memberId = ls_actionLink.match(/receiverId=([0-9]*)/i)[1];
  2000. ro_memberInfo[ls_memberId] = {
  2001. 'place': IC.Ikariam.getInt(IC.myGM.$('.place', ie_allyMemberRow).innerHTML),
  2002. 'score': IC.Ikariam.getInt(IC.myGM.$('.score', ie_allyMemberRow).innerHTML)
  2003. };
  2004. var ls_placeDifference = '-';
  2005. var ls_scoreDifference = '-';
  2006. if(!!lo_oldMemberInfo === true && !!lo_oldMemberInfo[ls_memberId] === true) {
  2007. ls_placeDifference = IC.Ikariam.formatToIkaNumber(lo_oldMemberInfo[ls_memberId]['place'] - ro_memberInfo[ls_memberId]['place'], true, true);
  2008. ls_scoreDifference = IC.Ikariam.formatToIkaNumber(ro_memberInfo[ls_memberId]['score'] - lo_oldMemberInfo[ls_memberId]['score'], true, true);
  2009. }
  2010. IC.myGM.addElement('span', IC.myGM.$('.place', ie_allyMemberRow), { 'innerHTML': ls_placeDifference });
  2011. IC.myGM.addElement('span', IC.myGM.$('.score', ie_allyMemberRow), { 'innerHTML': ls_scoreDifference });
  2012. });
  2013. ro_memberInfo['own'] = _lf_getOwnDataShowDifference(lo_oldMemberInfo);
  2014. return Promise.resolve(ro_memberInfo);
  2015. };
  2016. /**
  2017. * Add the span with the time of the last reset.
  2018. *
  2019. * @return {Promise}
  2020. * A Promise which resolves once the last reset time is added.
  2021. */
  2022. var _lf_addLastResetTime = async function() {
  2023. var li_lastResetTime = await IC.myGM.getValue(_ls_timeKey, 0);
  2024. var li_differenceInSec = ((new Date()).getTime() - li_lastResetTime) / 1000;
  2025. var ls_lastReset = IC.Language.$('highscore.memberInformation.noReset');
  2026. if(li_lastResetTime > 0) {
  2027. var li_days = Math.floor(li_differenceInSec / 86400);
  2028. var li_hours = Math.floor(li_differenceInSec / 3600) % 24;
  2029. var li_minutes = Math.floor(li_differenceInSec / 60) % 60;
  2030. ls_lastReset = li_days + 'd ' + li_hours + 'h ' + li_minutes + 'min';
  2031. }
  2032. IC.myGM.addElement('br', IC.myGM.$('#tab_highscore .content p'));
  2033. IC.myGM.addElement('span', IC.myGM.$('#tab_highscore .content p'), {
  2034. 'classes': ['bold', 'brown'],
  2035. 'innerHTML': IC.Language.$('highscore.memberInformation.lastReset', [ls_lastReset])
  2036. });
  2037. };
  2038. /**
  2039. * Prepare the highscore popup to show the data and show the data if requested.
  2040. *
  2041. * @return {Promise}
  2042. * A Promise which resolves once the popup is prepared.
  2043. */
  2044. var _lf_doPreparePopup = async function() {
  2045. _ls_dataKey = IC.Ikariam.serverCode + '_' + IC.ika.getModel().avatarAllyId + '_memberInfo_data_' + IC.myGM.getSelectValue('js_highscoreType', true, true);
  2046. _ls_timeKey = IC.Ikariam.serverCode + '_' + IC.ika.getModel().avatarAllyId + '_memberInfo_time_' + IC.myGM.getSelectValue('js_highscoreType', true, true);
  2047. _lf_addShowButton();
  2048. var lb_linkClicked = await IC.myGM.getValue('memberInfo_infoLinkClicked', false);
  2049. if(lb_linkClicked === true) {
  2050. await IC.myGM.deleteValue('memberInfo_infoLinkClicked');
  2051. _lo_data = await _lf_getDataShowDifference();
  2052. _lf_addResetButton();
  2053. _lf_addLastResetTime();
  2054. }
  2055. };
  2056. /**
  2057. * Update the settings to execute the callback or delete the handler.
  2058. *
  2059. * @param {boolean} ib_showMemberInformation
  2060. * If the user selected the checkbox to show the member information.
  2061. */
  2062. this.updateSettings = function(ib_showMemberInformation) {
  2063. if(ib_showMemberInformation === true) {
  2064. IC.RefreshHandler.add('highscore', 'memberInformation', _lf_doPreparePopup);
  2065. IC.myGM.addStyle(
  2066. '#' + IC.myGM.prefix + "resetInfo { float: right; margin-top: -6px; margin-right: 6px; } \
  2067. .highscore .score span { float: right; text-align: right; width: 70px; } \
  2068. .highscore .place span { float: right; text-align: right; width: 30px; } \
  2069. .highscore th:nth-child(4) { width: 30% !important; } \
  2070. .highscore th:nth-child(5) { width: 10% !important; } \
  2071. #tab_highscore .centerButton { margin: 10px 0px; }",
  2072. 'memberInformation', true
  2073. );
  2074. return;
  2075. }
  2076. IC.RefreshHandler.remove('highscore', 'memberInformation');
  2077. IC.myGM.removeStyle('memberInformation');
  2078. };
  2079. };
  2080. // Show the member information.
  2081. IC.Options.addCheckbox('showMemberInformation', 'diverseOptions', 1, false, IC.Language.$('highscore.options.showMemberInformation'), { changeCallback: _go_memberInformation.updateSettings });
  2082. })();
  2083. IC.con.logTimeStamp('IkariamEnhancedUI: highscore functions created');
  2084. // Message enhancements.
  2085. (function() {
  2086. /**
  2087. * Storage for the url replacement functions.
  2088. *
  2089. * @type {object}
  2090. */
  2091. var _go_replaceURL = new function() {
  2092. /**
  2093. * Show a warning when a replaced link is clicked.
  2094. */
  2095. var _lf_showNotification = function() {
  2096. var ls_urlToOpen = this.innerHTML.IC.decodeHTML();
  2097. var lo_notificationText = {
  2098. header: IC.Language.$('message.replacedUrl.notification.header'),
  2099. body: IC.Language.$('message.replacedUrl.notification.text', ['<span class="bold red">"' + ls_urlToOpen + '"</span>']),
  2100. confirm: IC.Language.$('general.yes'),
  2101. abort: IC.Language.$('general.no')
  2102. };
  2103. var lo_notificationCallback = {
  2104. confirm: function() { IC.win.open(ls_urlToOpen); },
  2105. abort: function() { /* Only set to show the abort button */ }
  2106. };
  2107. IC.myGM.notification(lo_notificationText, lo_notificationCallback);
  2108. };
  2109. /**
  2110. * Replace the links.
  2111. */
  2112. var _lf_doReplace = function() {
  2113. var la_messageBodys = IC.myGM.$$('.msgText');
  2114. la_messageBodys.forEach(function(ie_messageBody) {
  2115. var ls_text = ie_messageBody.innerHTML;
  2116. ie_messageBody.innerHTML = ls_text.replace(/(?:^|\s)(http(s?)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,4}(\/[^<\s]*)?)/g, ' <span class="' + IC.myGM.prefix + 'replacedUrl" title="$1">$1</span> ');
  2117. });
  2118. var la_replacedURLs = IC.myGM.$$('.' + IC.myGM.prefix + 'replacedUrl');
  2119. la_replacedURLs.forEach(function(ie_replacedURL) {
  2120. ie_replacedURL.addEventListener('click', _lf_showNotification, true);
  2121. });
  2122. };
  2123. /**
  2124. * Update the settings to execute the callback or delete the handler.
  2125. *
  2126. * @param {boolean} ib_replaceURL
  2127. * If the user selected the checkbox to replace the url.
  2128. */
  2129. this.updateSettings = function(ib_replaceURL) {
  2130. var la_postboxes = ['diplomacyAdvisor', 'diplomacyAdvisorOutBox', 'diplomacyAdvisorArchive', 'diplomacyAdvisorArchiveOutBox'];
  2131. if(ib_replaceURL === true) {
  2132. IC.RefreshHandler.add(la_postboxes, 'replaceURL', _lf_doReplace);
  2133. IC.myGM.addStyle(
  2134. '.' + IC.myGM.prefix + 'replacedUrl { font-weight: bold; font-style: italic; } \
  2135. .' + IC.myGM.prefix + 'replacedUrl:hover { text-decoration: underline; cursor: pointer; }',
  2136. 'replaceURL', true
  2137. );
  2138. return;
  2139. }
  2140. IC.RefreshHandler.remove(la_postboxes, 'replaceURL');
  2141. IC.myGM.removeStyle('replaceURL');
  2142. };
  2143. };
  2144. /**
  2145. * Storage for the inline message functions.
  2146. *
  2147. * @type {object}
  2148. */
  2149. var _go_inlineMessage = new function() {
  2150. /**
  2151. * Replace the links.
  2152. */
  2153. var _lf_doShowInline = function() {
  2154. var la_messageRows = IC.myGM.$$('#deleteMessages tr.entry');
  2155. var li_displayMaxCharacters = 60;
  2156. la_messageRows.forEach(function(ie_messageRow) {
  2157. var le_subject = IC.myGM.$('.subject', ie_messageRow);
  2158. var ls_typePrefix = /gmessage/.test(ie_messageRow.id) === true ? 'g' : '';
  2159. var ls_id = ie_messageRow.id.replace(ls_typePrefix + 'message', '');
  2160. var le_text = IC.myGM.$('#tbl_' + ls_typePrefix + 'mail' + ls_id + ' .msgText');
  2161. var ls_inlineText = le_text.innerHTML.replace(/<br>/gi, ' ').replace(/\s+/gi, ' ');
  2162. if(ls_inlineText.length > li_displayMaxCharacters)
  2163. ls_inlineText = ls_inlineText.substring(0, li_displayMaxCharacters - 6) + ' (...)';
  2164. le_subject.innerHTML += '<br><sub>' + ls_inlineText + '</sub>';
  2165. });
  2166. // Adjust the size of the Scrollbar.
  2167. IC.ika.controller.adjustSizes();
  2168. };
  2169. /**
  2170. * Update the settings to execute the callback or delete the handler.
  2171. *
  2172. * @param {boolean} ib_displayInlineMessage
  2173. * If the user selected the checkbox to display inline messages.
  2174. */
  2175. this.updateSettings = function(ib_displayInlineMessage) {
  2176. var la_postboxes = ['diplomacyAdvisor', 'diplomacyAdvisorOutBox', 'diplomacyAdvisorArchive', 'diplomacyAdvisorArchiveOutBox'];
  2177. if(ib_displayInlineMessage === true) {
  2178. IC.RefreshHandler.add(la_postboxes, 'inlineMessage', _lf_doShowInline);
  2179. return;
  2180. }
  2181. IC.RefreshHandler.remove(la_postboxes, 'inlineMessage');
  2182. };
  2183. };
  2184. /**
  2185. * Storage for the message signature functions.
  2186. *
  2187. * @type {object}
  2188. */
  2189. var _go_messageSignature = new function() {
  2190. /**
  2191. * Add the signature to a new message.
  2192. */
  2193. var _lf_addSignature = function() {
  2194. var ls_signature = '';
  2195. switch(IC.Options.getOption('messages', 'useMessageSignature')) {
  2196. case IC.Options.SpecificityLevel.GLOBAL:
  2197. ls_signature = IC.Options.getOption('messages', 'globalSignature');
  2198. break;
  2199. case IC.Options.SpecificityLevel.SERVER:
  2200. ls_signature = IC.Options.getOption('messages', 'serverSignature');
  2201. break;
  2202. case IC.Options.SpecificityLevel.PLAYER:
  2203. ls_signature = IC.Options.getOption('messages', 'playerSignature');
  2204. break;
  2205. }
  2206. if(ls_signature === '')
  2207. return;
  2208. var le_textarea = IC.myGM.$('#js_msgTextConfirm');
  2209. var ls_text = le_textarea.value;
  2210. if(IC.Options.getOption('messages', 'signaturePlacementTop'))
  2211. ls_text = '\n\n' + ls_signature + ls_text;
  2212. else
  2213. ls_text = ls_text + '\n\n' + ls_signature;
  2214. le_textarea.value = ls_text;
  2215. le_textarea.setSelectionRange(0,0);
  2216. le_textarea.focus();
  2217. };
  2218. /**
  2219. * Update the settings to execute the callback or delete the handler.
  2220. *
  2221. * @param {boolean} ib_addMessageSignature
  2222. * If the user selected the checkbox to add signatures to messages.
  2223. */
  2224. this.updateSettings = function(is_useMessageSignature) {
  2225. if(is_useMessageSignature === IC.Options.SpecificityLevel.GLOBAL
  2226. || is_useMessageSignature === IC.Options.SpecificityLevel.SERVER
  2227. || is_useMessageSignature === IC.Options.SpecificityLevel.PLAYER) {
  2228. IC.RefreshHandler.add('sendIKMessage', 'addMessageSignature', _lf_addSignature);
  2229. return;
  2230. }
  2231. IC.RefreshHandler.remove('sendIKMessage', 'addMessageSignature');
  2232. };
  2233. };
  2234. IC.Options.addWrapper('messages', IC.Language.$('message.options.wrapperTitle'));
  2235. // Replace urls.
  2236. IC.Options.addCheckbox('replaceURL', 'messages', 1, true, IC.Language.$('message.options.replaceURL'), { changeCallback: _go_replaceURL.updateSettings });
  2237. // Display message text teaser in overview.
  2238. IC.Options.addCheckbox('inlineMessage', 'messages', 1, true, IC.Language.$('message.options.inlineMessage'), { changeCallback: _go_inlineMessage.updateSettings });
  2239. // Player specific signatures.
  2240. var la_options = [
  2241. { value: 'none', label: IC.Language.$('message.options.signature.use.none') },
  2242. { value: IC.Options.SpecificityLevel.GLOBAL, label: IC.Language.$('message.options.signature.use.global') },
  2243. { value: IC.Options.SpecificityLevel.SERVER, label: IC.Language.$('message.options.signature.use.server') },
  2244. { value: IC.Options.SpecificityLevel.PLAYER, label: IC.Language.$('message.options.signature.use.player') }
  2245. ];
  2246. IC.Options.addSelect('useMessageSignature', 'messages', 2, IC.Options.SpecificityLevel.GLOBAL, IC.Language.$('message.options.signature.use.description'), la_options, { changeCallback: _go_messageSignature.updateSettings, 'specificity': IC.Options.SpecificityLevel.PLAYER });
  2247. // Place the signature on top.
  2248. IC.Options.addCheckbox('signaturePlacementTop', 'messages', 2, true, IC.Language.$('message.options.signature.placementTop'), {});
  2249. // Define a global signature.
  2250. IC.Options.addTextArea('globalSignature', 'messages', 3, '', IC.Language.$('message.options.signature.global'), {});
  2251. // Define a server specific signature.
  2252. IC.Options.addTextArea('serverSignature', 'messages', 4, '', IC.Language.$('message.options.signature.server'), { 'specificity': IC.Options.SpecificityLevel.SERVER });
  2253. // Define a server specific signature.
  2254. IC.Options.addTextArea('playerSignature', 'messages', 4, '', IC.Language.$('message.options.signature.player'), { 'specificity': IC.Options.SpecificityLevel.PLAYER });
  2255. })();
  2256. IC.con.logTimeStamp('IkariamEnhancedUI: message functions created');
  2257. // Troop information.
  2258. (function() {
  2259. /**
  2260. * Provider for data storages.
  2261. *
  2262. * @type {object}
  2263. */
  2264. var _go_storageProvider = new function() {
  2265. /**
  2266. * Constructor for troop list.
  2267. */
  2268. var _lf_troopList = function() {
  2269. /**
  2270. * Storage for troop information.
  2271. *
  2272. * @type {lf_troop[]}
  2273. */
  2274. var la_troopList = [];
  2275. /**
  2276. * Troop information storage.
  2277. *
  2278. * @param {string} is_name
  2279. * The name of the troop.
  2280. * @param {int} ii_number
  2281. * The number of the troop.
  2282. */
  2283. var lf_troop = function(is_name, ii_number) {
  2284. var ls_name = is_name;
  2285. var li_number = ii_number;
  2286. this.toString = function() {
  2287. return '\n' + ls_name + ': ' + li_number;
  2288. };
  2289. };
  2290. /**
  2291. * If the troop list contains no entries.
  2292. *
  2293. * @return {boolean}
  2294. * If the troop list is empty.
  2295. */
  2296. this.__defineGetter__('isEmpty', function() {
  2297. return la_troopList.length < 1;
  2298. });
  2299. /**
  2300. * Add a new troop to the troop list.
  2301. *
  2302. * @param {string} is_name
  2303. * The name of the troop.
  2304. * @param {int} ii_number
  2305. * The number of the troop.
  2306. */
  2307. this.addTroop = function(is_name, ii_number) {
  2308. la_troopList.push(new lf_troop(is_name, ii_number));
  2309. };
  2310. /**
  2311. * Transform the troop list to a string.
  2312. *
  2313. * @return {string}
  2314. * The string representation of the troop list.
  2315. */
  2316. this.toString = function() {
  2317. return la_troopList.join('');
  2318. };
  2319. };
  2320. /**
  2321. * Constructor for troop list of foreign player.
  2322. *
  2323. * @param {string} is_playerName
  2324. * The name of the player who owns the troops.
  2325. */
  2326. var _lf_foreignTroopList = function(is_playerName) {
  2327. /**
  2328. * The name of the player who owns the troops.
  2329. *
  2330. * @type {string}
  2331. */
  2332. var ls_playerName = is_playerName;
  2333. /**
  2334. * Storage for troop information.
  2335. *
  2336. * @type {_lf_troopList[]}
  2337. */
  2338. var lo_troopList = new _lf_troopList();
  2339. /**
  2340. * If the troop list contains no entries.
  2341. *
  2342. * @return {boolean}
  2343. * If the troop list is empty.
  2344. */
  2345. this.__defineGetter__('isEmpty', function() {
  2346. return lo_troopList.isEmpty;
  2347. });
  2348. /**
  2349. * Add a new troop to the troop list.
  2350. *
  2351. * @param {string} is_name
  2352. * The name of the troop.
  2353. * @param {int} ii_number
  2354. * The number of the troop.
  2355. */
  2356. this.addTroop = function(is_name, ii_number) {
  2357. lo_troopList.addTroop(is_name, ii_number);
  2358. };
  2359. /**
  2360. * Transform the troop list to a string.
  2361. *
  2362. * @return {string}
  2363. * The string representation of the troop list.
  2364. */
  2365. this.toString = function() {
  2366. return '\n* ' + ls_playerName + ' *' + lo_troopList;
  2367. };
  2368. };
  2369. /**
  2370. * Storage for multiple troop lists.
  2371. *
  2372. * @param {string} is_type
  2373. * The type of the troops (units / ships)
  2374. * @param {string} is_status
  2375. * The status of the troops (own / friends / enemies)
  2376. */
  2377. var _lf_troopListStorage = function(is_type, is_status) {
  2378. /**
  2379. * The type of the troops (units / ships).
  2380. *
  2381. * @type {string}
  2382. */
  2383. var ls_type = is_type;
  2384. /**
  2385. * The status of the troops (own / friends / enemies).
  2386. *
  2387. * @type {string}
  2388. */
  2389. var ls_status = is_status;
  2390. /**
  2391. * The troop lists.
  2392. *
  2393. * @type {(_lf_troopList||_lf_foreignTroopList)[]}
  2394. */
  2395. var la_troopLists = [];
  2396. /**
  2397. * The status of the troop lists (own / friends / enemies).
  2398. *
  2399. * @return {boolean}
  2400. * The status of the lists.
  2401. */
  2402. this.__defineGetter__('status', function() {
  2403. return ls_status;
  2404. });
  2405. /**
  2406. * Add a new troop list to the storage.
  2407. *
  2408. * @param {_lf_troopList||_lf_foreignTroopList} io_troopList
  2409. * The troop list to add.
  2410. */
  2411. this.addTroopList = function(io_troopList) {
  2412. la_troopLists.push(io_troopList);
  2413. };
  2414. /**
  2415. * Transform the troop list storage to a string.
  2416. *
  2417. * @return {string}
  2418. * The string representation of the troop list storage.
  2419. */
  2420. this.toString = function() {
  2421. return '\n--- ' + IC.Language.$('troopInformation.' + ls_type + '.' + ls_status) + ' ---' + la_troopLists.join('\n');
  2422. };
  2423. };
  2424. /**
  2425. * Storage for data of all troops of one type.
  2426. *
  2427. * @param {string} is_type
  2428. * The type of the troops (units / ships)
  2429. */
  2430. var _lf_troopData = function(is_type) {
  2431. /**
  2432. * The type of the troops (units / ships).
  2433. *
  2434. * @type {string}
  2435. */
  2436. var ls_type = is_type;
  2437. /**
  2438. * The troop list storages.
  2439. *
  2440. * @type {_lf_troopListStorage[]}
  2441. */
  2442. var la_listStorages = [];
  2443. /**
  2444. * If the troop list contains no entries.
  2445. *
  2446. * @return {boolean}
  2447. * If the troop list is empty.
  2448. */
  2449. this.__defineGetter__('isEmpty', function() {
  2450. return la_listStorages.length < 1;
  2451. });
  2452. /**
  2453. * Add a new troop list to the storage.
  2454. *
  2455. * @param {string} is_status
  2456. * The status of the troop list.
  2457. * @param {_lf_troopList||_lf_foreignTroopList} io_troopList
  2458. * The troop list to add.
  2459. */
  2460. this.addTroopList = function(is_status, io_troopList) {
  2461. for(var i = 0; i < la_listStorages.length; i++) {
  2462. if(la_listStorages[i].status === is_status) {
  2463. la_listStorages[i].addTroopList(io_troopList);
  2464. return;
  2465. }
  2466. }
  2467. var lo_listStorage = new _lf_troopListStorage(ls_type, is_status);
  2468. lo_listStorage.addTroopList(io_troopList);
  2469. la_listStorages.push(lo_listStorage);
  2470. };
  2471. /**
  2472. * Transform the troop data to a string.
  2473. *
  2474. * @param {string} is_townInformation
  2475. * The information about the town for which the troop data is displayed.
  2476. *
  2477. * @return {string}
  2478. * The string representation of the troop data.
  2479. */
  2480. this.getString = function(is_townInformation) {
  2481. return '===== ' + IC.Language.$('troopInformation.' + ls_type + '.label', [is_townInformation]) + ' =====' + la_listStorages.join('\n\n');
  2482. };
  2483. };
  2484. /**
  2485. * Get a new troop list representation for own troops.
  2486. *
  2487. * @return {_lf_troopList}
  2488. * The troop list.
  2489. */
  2490. this.ownTroopList = function() {
  2491. return new _lf_troopList();
  2492. };
  2493. /**
  2494. * Get a new troop list representation for foreign troops.
  2495. *
  2496. * @param {string} is_playerName
  2497. * The name of the player who owns the troops.
  2498. *
  2499. * @return {_lf_foreignTroopList}
  2500. * The troop list.
  2501. */
  2502. this.foreignTroopList = function(is_playerName) {
  2503. return new _lf_foreignTroopList(is_playerName);
  2504. };
  2505. /**
  2506. * Get a new troop data storage representation for all troops of one type.
  2507. *
  2508. * @param {string} is_type
  2509. * The type of the troops (units / ships).
  2510. *
  2511. * @return {_lf_troopData}
  2512. * The troop data storage.
  2513. */
  2514. this.troopData = function(is_type) {
  2515. return new _lf_troopData(is_type);
  2516. };
  2517. };
  2518. /**
  2519. * Storage for the dta extraction functions.
  2520. *
  2521. * @type {object}
  2522. */
  2523. var _go_dataExtractor = new function() {
  2524. /**
  2525. * Extract own troops from a wrapper.
  2526. *
  2527. * @param {element} ie_wrapper
  2528. * The wrapper to extract the troops from.
  2529. *
  2530. * @return {_go_storageProvider.ownTroopList[]}
  2531. * The extracted troops.
  2532. */
  2533. var _lf_extractOwnTroops = function(ie_wrapper) {
  2534. var la_nameCells = IC.myGM.$$('.table01 .title_img_row th .tooltip', ie_wrapper);
  2535. var la_numberCells = IC.myGM.$$('.table01 .count td', ie_wrapper);
  2536. var ro_troops = _go_storageProvider.ownTroopList();
  2537. for(var i = 0; i < la_nameCells.length; i++) {
  2538. var li_number = IC.Ikariam.getInt(la_numberCells[i].innerHTML);
  2539. if(li_number > 0)
  2540. ro_troops.addTroop(la_nameCells[i].innerHTML, li_number);
  2541. }
  2542. return ro_troops;
  2543. };
  2544. /**
  2545. * Extract foreign troops from a wrapper.
  2546. *
  2547. * @param {element} ie_wrapper
  2548. * The wrapper to extract the troops from.
  2549. *
  2550. * @return {_go_storageProvider.foreignTroopList[]}
  2551. * The extracted troops.
  2552. */
  2553. var _lf_extractForeignTroops = function(ie_wrapper) {
  2554. var la_nameCells = IC.myGM.$$('.table01 .title_img_row th:not(:first-child) .tooltip', ie_wrapper);
  2555. var la_numberRows = IC.myGM.$$('.table01 tr:not(.title_img_row)', ie_wrapper);
  2556. var lo_numberCells = {};
  2557. for(var i = 0; i < la_numberRows.length; i++) {
  2558. var ls_playerName = IC.myGM.$('td a', la_numberRows[i]).innerHTML.trim();
  2559. if(!lo_numberCells[ls_playerName]) {
  2560. lo_numberCells[ls_playerName] = [];
  2561. }
  2562. lo_numberCells[ls_playerName] = lo_numberCells[ls_playerName].concat(IC.myGM.$$('td:not(:first-child)', la_numberRows[i]));
  2563. }
  2564. var ra_troops = [];
  2565. IC.myGM.forEach(lo_numberCells, function (is_playerName, ia_numberCells) {
  2566. var lo_playerTroops = _go_storageProvider.foreignTroopList(is_playerName);
  2567. for(var i = 0; i < la_nameCells.length; i++) {
  2568. var li_number = IC.Ikariam.getInt(ia_numberCells[i].innerHTML);
  2569. if(li_number > 0)
  2570. lo_playerTroops.addTroop(la_nameCells[i].innerHTML, li_number);
  2571. }
  2572. if(lo_playerTroops.isEmpty === false)
  2573. ra_troops.push(lo_playerTroops);
  2574. });
  2575. return ra_troops;
  2576. };
  2577. /**
  2578. * Extract all troop of one type.
  2579. *
  2580. * @param {string} is_type
  2581. * The type of the troops to extract (units / ships).
  2582. * @param {string} is_wrapperTabId
  2583. * The id of the tab which contains the wrappers.
  2584. *
  2585. * @return {_go_storageProvider.troopData}
  2586. * The extracted data.
  2587. */
  2588. var _lf_extractTroops = function(is_type, is_wrapperTabId) {
  2589. var ro_return = _go_storageProvider.troopData(is_type);
  2590. var la_wrappers = IC.myGM.$$('#' + is_wrapperTabId + ' .contentBox01h');
  2591. var lo_ownTroops = _lf_extractOwnTroops(la_wrappers[0]);
  2592. if(lo_ownTroops.isEmpty === false)
  2593. ro_return.addTroopList('own', lo_ownTroops);
  2594. var la_foreignStatus = ['friends', 'enemies'];
  2595. for(var i = 0; i < la_foreignStatus.length; i++) {
  2596. var la_foreignTroops = _lf_extractForeignTroops(la_wrappers[i + 2]);
  2597. for(var j = 0; j < la_foreignTroops.length; j++) {
  2598. ro_return.addTroopList(la_foreignStatus[i], la_foreignTroops[j]);
  2599. }
  2600. }
  2601. return ro_return;
  2602. };
  2603. /**
  2604. * Extract all troop from the popup.
  2605. *
  2606. * @return {object}
  2607. * All extracted troops.
  2608. * Signature: { units: <_go_storageProvider.troopData>, ships: <_go_storageProvider.troopData> }
  2609. */
  2610. this.extract = function() {
  2611. return {
  2612. units: _lf_extractTroops('units', 'tabUnits'),
  2613. ships: _lf_extractTroops('ships', 'tabShips')
  2614. };
  2615. };
  2616. };
  2617. /**
  2618. * Storage for the troop information functions.
  2619. *
  2620. * @type {object}
  2621. */
  2622. var _go_troopInformation = new function() {
  2623. /**
  2624. * Show the troop information popup.
  2625. *
  2626. * @param {object} io_data
  2627. * All extracted troop.
  2628. * Signature: { units: <_go_storageProvider.troopData>, ships: <_go_storageProvider.troopData> }
  2629. */
  2630. var _ls_showPopup = function(io_data) {
  2631. var la_output = [];
  2632. var ls_townInformation = (function() {
  2633. var lo_allTowns = IC.ika.getModel().relatedCityData;
  2634. var lo_selectedTown = lo_allTowns[lo_allTowns.selectedCity];
  2635. return lo_selectedTown.name + ' ' + lo_selectedTown.coords;
  2636. })();
  2637. if(!!io_data === true) {
  2638. if(!!io_data.units.isEmpty === false)
  2639. la_output.push(io_data.units.getString(ls_townInformation));
  2640. if(!!io_data.ships.isEmpty === false)
  2641. la_output.push(io_data.ships.getString(ls_townInformation));
  2642. }
  2643. var ls_output = la_output.join('\n\n-------------------------------------------------------------------------------------\n\n');
  2644. if(ls_output.length === 0)
  2645. ls_output = IC.Language.$('troopInformation.noTroops', [ls_townInformation]);
  2646. var lo_text = {
  2647. header: IC.Language.$('troopInformation.header', [ls_townInformation]),
  2648. body: ls_output
  2649. };
  2650. IC.myGM.notification(lo_text, null, { textarea: true, readonly: true, autoselect: true });
  2651. };
  2652. /**
  2653. * Extract the data and show the popup.
  2654. */
  2655. var _lf_showInformation = function() {
  2656. _ls_showPopup(_go_dataExtractor.extract());
  2657. };
  2658. /**
  2659. * Show the troop information link.
  2660. */
  2661. var _lf_doShowTroopInformationLink = function() {
  2662. var le_button = IC.myGM.addButton(IC.myGM.$('#cityMilitary_c .buildingDescription'), IC.Language.$('troopInformation.button'), _lf_showInformation, true);
  2663. var la_cssRules = [['position', 'absolute'], ['top', '5px'], ['right', '20px']];
  2664. for(var i = 0; i < la_cssRules.length; i++) {
  2665. le_button.style[la_cssRules[i][0]] = la_cssRules[i][1];
  2666. }
  2667. };
  2668. /**
  2669. * Update the settings to execute the callback or delete the handler.
  2670. *
  2671. * @param {boolean} ib_enableTroopInformation
  2672. * If the user selected the checkbox to show the troop information.
  2673. */
  2674. this.updateSettings = function(ib_enableTroopInformation) {
  2675. if(ib_enableTroopInformation === true) {
  2676. IC.RefreshHandler.add('cityMilitary', 'troopInformation', _lf_doShowTroopInformationLink);
  2677. return;
  2678. }
  2679. IC.RefreshHandler.remove('cityMilitary', 'troopInformation');
  2680. };
  2681. };
  2682. /**
  2683. * Storage for the link barracks and shipyard functions.
  2684. *
  2685. * @type {object}
  2686. */
  2687. var _go_linkBarrackShipyard = new function() {
  2688. /**
  2689. * Adds a link to the container.
  2690. *
  2691. * @param {String} is_type
  2692. * The link type (units / fleet).
  2693. * @param {Element} ie_container
  2694. * The element which should be container for the link.
  2695. */
  2696. var _lf_addLink = function(is_type, ie_container) {
  2697. var lo_data = IC.ika.getScreen().data;
  2698. var ls_linkText = is_type === 'units' ? IC.Language.$('troopInformation.link.gotoBarracks') : IC.Language.$('troopInformation.link.gotoShipyard');
  2699. ls_linkText = '(' + ls_linkText + ')';
  2700. var ls_buildingType = is_type === 'units' ? 'barracks' : 'shipyard';
  2701. var li_position = -1;
  2702. for(var i = 0; i < lo_data.position.length; i++) {
  2703. if(lo_data.position[i].building === ls_buildingType) {
  2704. li_position = i;
  2705. break;
  2706. }
  2707. }
  2708. if(li_position >= 0) {
  2709. var ls_href = '?view=%building%&cityId=%cityId%&position=%position%'
  2710. .replace(/%building%/gi, ls_buildingType)
  2711. .replace(/%cityId%/gi, lo_data.id)
  2712. .replace(/%position%/gi, li_position);
  2713. IC.myGM.addElement('a', ie_container, {
  2714. innerHTML: ls_linkText,
  2715. href: ls_href,
  2716. onclick: 'ajaxHandlerCall(this.href);return false;',
  2717. style: [['margin-left', '5px']]
  2718. });
  2719. }
  2720. };
  2721. /**
  2722. * Link barack and shipyard from troop overview screen.
  2723. */
  2724. var _lf_doLinkBarrackShipyardOverview = function() {
  2725. var le_container = IC.myGM.$('.header', IC.myGM.$('#tabUnits'));
  2726. _lf_addLink('units', le_container);
  2727. le_container = IC.myGM.$('.header', IC.myGM.$('#tabShips'));
  2728. _lf_addLink('fleet', le_container);
  2729. };
  2730. /**
  2731. * Link barrack and shipyard in dismiss units screen.
  2732. */
  2733. var _lf_doLinkBarrackShipyardDismiss = function() {
  2734. var ls_type = IC.myGM.$('#js_garrisonEditForm input[name=function]').value.replace(/fire/gi, '').toLowerCase();
  2735. var le_container = IC.myGM.$('#js_garrisonEditForm .header');
  2736. _lf_addLink(ls_type, le_container);
  2737. };
  2738. /**
  2739. * Update the settings to execute the callback or delete the handler.
  2740. *
  2741. * @param {boolean} ib_linkBarrackShipyard
  2742. * If the user selected the checkbox to link barrackand shipyard.
  2743. */
  2744. this.updateSettings = function(ib_linkBarrackShipyard) {
  2745. if(ib_linkBarrackShipyard === true) {
  2746. IC.RefreshHandler.add('cityMilitary', 'linkBarrackShipyardOverview', _lf_doLinkBarrackShipyardOverview);
  2747. IC.RefreshHandler.add('garrisonEdit', 'linkBarrackShipyardDismiss', _lf_doLinkBarrackShipyardDismiss);
  2748. return;
  2749. }
  2750. IC.RefreshHandler.remove('cityMilitary', 'linkBarrackShipyardOverview');
  2751. IC.RefreshHandler.remove('garrisonEdit', 'linkBarrackShipyardDismiss');
  2752. };
  2753. };
  2754. IC.Options.addCheckbox('showTroopInformation', 'diverseOptions', 1, true, IC.Language.$('troopInformation.options.show'), { changeCallback: _go_troopInformation.updateSettings });
  2755. IC.Options.addCheckbox('linkBarrackShipyard', 'diverseOptions', 1, true, IC.Language.$('troopInformation.options.linkBarrackShipyard'), { changeCallback: _go_linkBarrackShipyard.updateSettings });
  2756. })();
  2757. IC.con.logTimeStamp('IkariamEnhancedUI: troop information functions created');
  2758. IC.con.groupEnd();
  2759. }
  2760.  
  2761. /**
  2762. * Main function of the script.<br>
  2763. * Inits the Ikariam Core and calls the script functions.<br>
  2764. * Must be called with <pre>setTimeout(main, 0)</pre> for correct setting of some core variables.
  2765. */
  2766. async function main() {
  2767. // Get the Ikariam core.
  2768. var IC = new IkariamCore('4.1', 4369, 'Ikariam Enhanced UI', 'Tobbe', false);
  2769. if(IC.myGM.alreadyExecuted === true)
  2770. return;
  2771. await IC.Language.setDefaultLanguage('en');
  2772. await IC.Language.addLanguageText('en', {"view": {"options": {"wrapperTitle":"View","moveLoadingCircle":"Move loading circle to position bar","hideBirds":"Hide the bird swarm","noVerticalCenterInTownAdvisor":"Don't center town information in the town advisor"}},"island": {"options": {"showColonizingCityInfo":"Show information about colonizing cities"}},"finance": {"options": {"showIncomeOnTop":"Show income on top in balance view","shortUpkeepReductionTable":"Show a short version of the upkeep reduction"},"income": {"perHour":"Income per hour","perDay":"Income per day","start":"Income without reduction"},"upkeep": {"reason": {"0":"Troops","1":"Ships","2":"Troops & Ships"},"basic":"Basic Costs","supply":"Supply Costs","result":"Total Costs"}},"missingResources": {"options": {"wrapperTitle":"Missing Resources","show":"Show missing resources in construction view","showPositive":"Show also the remaining resources after an upgrade","showColoured":"Show the remaining resources coloured"}},"tooltips": {"options": {"autoshow":"Show tooltips in alliance mebers view and military advisor automatically","showDirectInMilitaryAdvisor":"Show information about cargo / fleets in military view without tooltips"}},"zoom": {"options": {"wrapperTitle":"Zoom function","zoomView":"Activate zoom in world view, island view, town view","factor": {"world":"Zoom worldmap:","island":"Zoom island view:","town":"Zoom town view:"},"scaleChildren": {"label":"Let banners and symbols in normal size when zooming when zooming in this view:","world":"Worldmap","island":"Island view","town":"Town view"},"accessKeyLabel":"This keys must be pressed to zoom with the mouse:"},"zoomIn":"Zoom in","factor":"Zoom factor","zoomOut":"Zoom out"},"resourceInformation": {"options": {"wrapperTitle":"Resource Information","resourceQuicklinkEnhancements":"Link resource number to town hall / mines","directIncome": {"show":"Show the hourly income directly in town view","style": {"label":"Style of the hourly income in town view:","alignRight":"Right align","alignLeft":"Left align","withSeparation":"Right align with separation"}},"capacityBar": {"show":"Show info bar for warehouse capacity","hasBorder":"Has border","showBranchOfficeResources":"Show resources in trading post","orientation": {"label":"Orientation of the bar","vertical":"Vertical","horizontal":"Horizontal","horizontalFull":"Horizontal, full length"}}},"dailyProduction":"Daily production %$1:","dailyExpenses":"Daily expenses %$1:"},"highscore": {"options": {"showMemberInformation":"Enable the possibility to save highscore data of alliance members"},"memberInformation": {"show":"Alliance info","reset":"Reset","lastReset":"Time since the last reset: %$1","noReset":"No reset so far."}},"message": {"options": {"wrapperTitle":"Messages","replaceURL":"Make links in messages clickable","inlineMessage":"Embed the first few characters of each message in the messages overview","signature": {"use": {"description":"Use this signature:","none":"No signature","global":"Global signature","server":"Server signature","player":"Player signature"},"placementTop":"Insert signature above cited messages","global":"Global signature, which would be used on every world:","server":"Server signature, which only would be used on this world:","player":"Player signature, which only would be used for this player:"}},"replacedUrl": {"notification": {"header":"Attention!","text":"You're going to open the link %$1. This happens on your own risk. Proceed?"}}},"troopInformation": {"options": {"show":"Show troop info","linkBarrackShipyard":"Link barracks and shipyard from troop overview and dismiss units screen"},"link": {"gotoBarracks":"goto barracks","gotoShipyard":"goto shipyard"},"units": {"label":"Units in %$1","own":"Own units","friends":"Allied units","enemies":"Enemy units"},"ships": {"label":"Ships in %$1","own":"Own ships","friends":"Allied ships","enemies":"Enemy ships"},"button":"Troop information","header":"Troops in %$1","noTroops":"There are no troops in %$1"},"diverse": {"options": {"wrapperTitle":"Diverse"},"name": {"resource": {"gold":"Gold","wood":"Building Material","wine":"Wine","marble":"Marble","glass":"Crystal Glass","sulfur":"Sulphur"},"unit": {"swordsman":"Swordsman","phalanx":"Hoplite","archer":"Archer","marksman":"Sulphur Carabineer","mortar":"Mortar","slinger":"Slinger","catapult":"Catapult","ram":"Battering Ram","steamgiant":"Steam Giant","bombardier":"Balloon-Bombardier","cook":"Cook","medic":"Doctor","girocopter":"Gyrocopter","spearman":"Spearman","spartan":"Spartan"},"ship": {"ballista":"Ballista Ship","catapult":"Catapult Ship","flamethrower":"Fire Ship","mortar":"Mortar Ship","ram":"Ram Ship","steamboat":"Steam Ram","rocketship":"Rocket Ship","submarine":"Diving Boat","paddlespeedship":"Paddle Speedboat","ballooncarrier":"Balloon Carrier","tender":"Tender","transport":"Merchant Ship"}}}});
  2773. var la_language = ['de', 'gr', 'fr', 'it', 'lv', 'ru', 'tr'];
  2774. for(var i = 0; i < la_language.length; i++) {
  2775. await IC.Language.registerLanguageResource(la_language[i], la_language[i], 'https://resources.ikascripts.de/IkariamEnhancedUI/v4.1/' + la_language[i] + '.json');
  2776. }
  2777. // Instantiate the ui script.
  2778. new EnhancedUI(IC);
  2779. }
  2780.  
  2781. // Call the main function of the script.
  2782. setTimeout(main, 0);