Ticket #3934: resource_agnostic-v7.2.patch
File resource_agnostic-v7.2.patch, 109.1 KB (added by , 8 years ago) |
---|
-
new file inaries/data/mods/public/globalscripts/Resources.js
diff --git a/binaries/data/mods/public/globalscripts/Resources.js b/binaries/data/mods/public/globalscripts/Resources.js new file mode 100644 index 0000000..f07a80a
- + 1 /** 2 * Resources Global 3 * 4 * Engine.FindJSONFiles only exists within the session context 5 * Engine.BuildDirEntList only exists within the gui context 6 * The AI and test contexts have no access to any JSON file access functions 7 */ 8 function Resources() 9 { 10 let jsonFiles = []; 11 if (Engine.FindJSONFiles) 12 { 13 jsonFiles = Engine.FindJSONFiles("resources", false); 14 for (let file in jsonFiles) 15 jsonFiles[file] = "resources/" + jsonFiles[file] + ".json"; 16 } 17 else if (Engine.BuildDirEntList) 18 jsonFiles = Engine.BuildDirEntList("simulation/data/resources/", "*.json", false); 19 else 20 { 21 warn("Resources: No JSON access functions are unavailable"); 22 return; 23 } 24 25 this.resourceData = []; 26 this.resourceCodes = []; 27 28 for (let filename of jsonFiles) 29 { 30 let data = Engine.ReadJSONFile(filename); 31 if (!data) 32 continue; 33 34 data.subtypeNames = data.subtypes; 35 data.subtypes = Object.keys(data.subtypes); 36 37 this.resourceData.push(data); 38 if (data.enabled) 39 this.resourceCodes.push(data.code); 40 } 41 }; 42 43 Resources.prototype.GetData = function() 44 { 45 return this.resourceData.filter(resource => resource.enabled); 46 }; 47 48 Resources.prototype.GetResource = function(type) 49 { 50 let lType = type.toLowerCase(); 51 return this.GetData().find(resource => resource.code == lType); 52 }; 53 54 Resources.prototype.GetCodes = function() 55 { 56 return this.resourceCodes; 57 }; 58 59 /** 60 * Returns an object containing untranslated resource names mapped to 61 * resource codes. Includes subtypes. 62 */ 63 Resources.prototype.GetNames = function() 64 { 65 let names = {}; 66 for (let res of this.GetData()) 67 { 68 names[res.code] = res.name; 69 for (let subres of res.subtypes) 70 names[subres] = res.subtypeNames[subres] 71 } 72 return names; 73 }; -
binaries/data/mods/public/gui/common/functions_utility.js
diff --git a/binaries/data/mods/public/gui/common/functions_utility.js b/binaries/data/mods/public/gui/common/functions_utility.js index 9984cb0..bbb1a35 100644
a b function formatPlayerInfo(playerDataArray, playerStates) 416 416 417 417 return teamDescription.join("\n\n"); 418 418 } 419 420 /** 421 * Horizontally fit objects within a parent. 422 * 423 * @param margin - The gap, in px, between the repeated objects 424 * @param limit - The number of elements to fit 425 */ 426 function horizontallyDistributeObjects(parentName, margin = 0, limit = undefined) 427 { 428 let objects = Engine.GetGUIObjectByName(parentName).children; 429 if (limit) 430 objects = objects.splice(0, limit); 431 432 let i = 0; 433 for (let child of objects) 434 { 435 let size = child.size; 436 size.rleft = 100 / objects.length * i; 437 size.rright = 100 / objects.length * (i + 1); 438 size.right = -margin; 439 child.size = size; 440 ++i; 441 } 442 } 443 444 /** 445 * Hide all children after a certain index 446 * 447 * @param idx - The index from which to start 448 */ 449 function hideRemaining(parentName, idx = 0) 450 { 451 let objects = Engine.GetGUIObjectByName(parentName).children; 452 453 for (; idx < objects.length; ++idx) 454 objects[idx].hidden = true; 455 } -
binaries/data/mods/public/gui/common/l10n.js
diff --git a/binaries/data/mods/public/gui/common/l10n.js b/binaries/data/mods/public/gui/common/l10n.js index 53c16c2..3fd4570 100644
a b 1 const localisedResourceNames = {2 "firstWord": {3 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.4 "food": translateWithContext("firstWord", "Food"),5 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.6 "meat": translateWithContext("firstWord", "Meat"),7 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.8 "metal": translateWithContext("firstWord", "Metal"),9 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.10 "ore": translateWithContext("firstWord", "Ore"),11 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.12 "rock": translateWithContext("firstWord", "Rock"),13 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.14 "ruins": translateWithContext("firstWord", "Ruins"),15 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.16 "stone": translateWithContext("firstWord", "Stone"),17 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.18 "treasure": translateWithContext("firstWord", "Treasure"),19 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.20 "tree": translateWithContext("firstWord", "Tree"),21 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.22 "wood": translateWithContext("firstWord", "Wood"),23 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.24 "fruit": translateWithContext("firstWord", "Fruit"),25 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.26 "grain": translateWithContext("firstWord", "Grain"),27 // Translation: Word as used at the beginning of a sentence or as a single-word sentence.28 "fish": translateWithContext("firstWord", "Fish"),29 },30 "withinSentence": {31 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).32 "food": translateWithContext("withinSentence", "Food"),33 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).34 "meat": translateWithContext("withinSentence", "Meat"),35 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).36 "metal": translateWithContext("withinSentence", "Metal"),37 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).38 "ore": translateWithContext("withinSentence", "Ore"),39 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).40 "rock": translateWithContext("withinSentence", "Rock"),41 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).42 "ruins": translateWithContext("withinSentence", "Ruins"),43 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).44 "stone": translateWithContext("withinSentence", "Stone"),45 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).46 "treasure": translateWithContext("withinSentence", "Treasure"),47 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).48 "tree": translateWithContext("withinSentence", "Tree"),49 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).50 "wood": translateWithContext("withinSentence", "Wood"),51 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).52 "fruit": translateWithContext("withinSentence", "Fruit"),53 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).54 "grain": translateWithContext("withinSentence", "Grain"),55 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).56 "fish": translateWithContext("withinSentence", "Fish"),57 }58 };59 1 60 function getLocalizedResourceName(resource Code, context)2 function getLocalizedResourceName(resourceName, context) 61 3 { 62 if (!localisedResourceNames[context]) 63 { 64 warn("Internationalization: Unexpected context for resource type localization found: ‘" + context + "’. This context is not supported."); 65 return resourceCode; 66 } 67 if (!localisedResourceNames[context][resourceCode]) 68 { 69 warn("Internationalization: Unexpected resource type found with code ‘" + resourceCode + ". This resource type must be internationalized."); 70 return resourceCode; 71 } 72 return localisedResourceNames[context][resourceCode]; 4 return translateWithContext(context, resourceName); 73 5 } 74 6 75 7 /** … … function getLocalizedResourceAmounts(resources) 81 13 .filter(type => resources[type] > 0) 82 14 .map(type => sprintf(translate("%(amount)s %(resourceType)s"), { 83 15 "amount": resources[type], 84 "resourceType": getLocalizedResourceName(type, "withinSentence")16 "resourceType": translateWithContext("withinSentence", type) 85 17 })); 86 18 87 19 if (amounts.length > 1) -
binaries/data/mods/public/gui/common/tooltips.js
diff --git a/binaries/data/mods/public/gui/common/tooltips.js b/binaries/data/mods/public/gui/common/tooltips.js index ada0ca7..0fe4e0b 100644
a b function getEntityCostComponentsTooltipString(template, trainNum, entity) 342 342 343 343 return costs; 344 344 } 345 345 346 function getGatherTooltip(template) 346 347 { 347 348 if (!template.gather) -
binaries/data/mods/public/gui/session/diplomacy_window.xml
diff --git a/binaries/data/mods/public/gui/session/diplomacy_window.xml b/binaries/data/mods/public/gui/session/diplomacy_window.xml index 1708159..8857a57 100644
a b 1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 3 3 <object name="diplomacyDialogPanel" 4 size="50%- 300 50%-200 50%+300 50%+150"4 size="50%-260 50%-200 50%+260 50%+150" 5 5 type="image" 6 6 hidden="true" 7 7 sprite="ModernDialog" … … 11 11 </object> 12 12 13 13 <object name="diplomacyHeader" size="32 32 100%-32 64"> 14 <object name="diplomacyHeaderName" size="0 0 1 50 100%" type="text" style="chatPanel" ghost="true">14 <object name="diplomacyHeaderName" size="0 0 140 100%" type="text" style="chatPanel" ghost="true" text_align="center"> 15 15 <translatableAttribute id="caption">Name</translatableAttribute> 16 16 </object> 17 17 <object name="diplomacyHeaderCiv" size="150 0 250 100%" type="text" style="chatPanel" ghost="true"> … … 23 23 <object name="diplomacyHeaderTheirs" size="300 0 360 100%" type="text" style="chatPanel" ghost="true"> 24 24 <translatableAttribute id="caption">Theirs</translatableAttribute> 25 25 </object> 26 <object name="diplomacyHeaderAlly" size=" 100%-180 0 100%-160 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold">26 <object name="diplomacyHeaderAlly" size="360 0 380 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold"> 27 27 <translatableAttribute id="caption">A</translatableAttribute> 28 28 <translatableAttribute id="tooltip">Ally</translatableAttribute> 29 29 </object> 30 <object name="diplomacyHeaderNeutral" size=" 100%-160 0 100%-140 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold">30 <object name="diplomacyHeaderNeutral" size="380 0 400 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold"> 31 31 <translatableAttribute id="caption">N</translatableAttribute> 32 32 <translatableAttribute id="tooltip">Neutral</translatableAttribute> 33 33 </object> 34 <object name="diplomacyHeaderEnemy" size=" 100%-140 0 100%-120 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold">34 <object name="diplomacyHeaderEnemy" size="400 0 420 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold"> 35 35 <translatableAttribute id="caption">E</translatableAttribute> 36 36 <translatableAttribute id="tooltip">Enemy</translatableAttribute> 37 37 </object> 38 <object name="diplomacyHeaderTribute" size=" 100%-110 0 100% 100%" type="text" style="chatPanel">38 <object name="diplomacyHeaderTribute" size="430 0 100%-30 100%" type="text" style="chatPanel" text_align="center"> 39 39 <translatableAttribute id="caption">Tribute</translatableAttribute> 40 40 </object> 41 41 </object> … … 48 48 <object name="diplomacyPlayerTheirs[n]" size="300 0 360 100%" type="text" style="chatPanel" ghost="true"/> 49 49 50 50 <!-- Diplomatic stance - selection --> 51 <object name="diplomacyPlayerAlly[n]" size=" 100%-180 0 100%-160 100%" type="button" style="StoneButton" hidden="true"/>52 <object name="diplomacyPlayerNeutral[n]" size=" 100%-160 0 100%-140 100%" type="button" style="StoneButton" hidden="true"/>53 <object name="diplomacyPlayerEnemy[n]" size=" 100%-140 0 100%-120 100%" type="button" style="StoneButton" hidden="true"/>51 <object name="diplomacyPlayerAlly[n]" size="360 0 380 100%" type="button" style="StoneButton" hidden="true"/> 52 <object name="diplomacyPlayerNeutral[n]" size="380 0 400 100%" type="button" style="StoneButton" hidden="true"/> 53 <object name="diplomacyPlayerEnemy[n]" size="400 0 420 100%" type="button" style="StoneButton" hidden="true"/> 54 54 55 55 <!-- Tribute --> 56 <object name="diplomacyPlayerTributeFood[n]" size="100%-110 0 100%-90 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true"> 57 <object name="diplomacyPlayerTributeFoodImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/food.png" ghost="true"/> 58 </object> 59 <object name="diplomacyPlayerTributeWood[n]" size="100%-90 0 100%-70 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true"> 60 <object name="diplomacyPlayerTributeWoodImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/wood.png" ghost="true"/> 61 </object> 62 <object name="diplomacyPlayerTributeStone[n]" size="100%-70 0 100%-50 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true"> 63 <object name="diplomacyPlayerTributeStoneImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/stone.png" ghost="true"/> 64 </object> 65 <object name="diplomacyPlayerTributeMetal[n]" size="100%-50 0 100%-30 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true"> 66 <object name="diplomacyPlayerTributeMetalImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/metal.png" ghost="true"/> 56 <object size="430 0 100%-40 100%"> 57 <repeat count="8" var="r"> 58 <object name="diplomacyPlayer[n]_tribute[r]" size="0 0 20 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true"> 59 <object name="diplomacyPlayer[n]_tribute[r]_image" type="image" size="0 0 100% 100%" ghost="true"/> 60 </object> 61 </repeat> 67 62 </object> 68 63 69 64 <object name="diplomacyAttackRequest[n]" size="100%-20 0 100% 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true"> -
binaries/data/mods/public/gui/session/menu.js
diff --git a/binaries/data/mods/public/gui/session/menu.js b/binaries/data/mods/public/gui/session/menu.js index 494bd14..e6c2cf9 100644
a b const INITIAL_MENU_POSITION = "100%-164 " + MENU_TOP + " 100% " + MENU_BOTTOM; 22 22 // Number of pixels per millisecond to move 23 23 const MENU_SPEED = 1.2; 24 24 25 // Available resources in trade and tribute menu26 const RESOURCES = ["food", "wood", "stone", "metal"];27 28 25 // Trade menu: step for probability changes 29 26 const STEP = 5; 30 27 … … function closeChat() 227 224 Engine.GetGUIObjectByName("chatDialogPanel").hidden = true; 228 225 } 229 226 227 function initDiplomacy() 228 { 229 let dialog = Engine.GetGUIObjectByName("diplomacyDialogPanel"); 230 let size = dialog.size; 231 let width = size.right - size.left; 232 233 let tribSize = Engine.GetGUIObjectByName("diplomacyPlayer[0]_tribute[0]").size; 234 width += g_ResourceData.GetCodes().length * (tribSize.right - tribSize.left); 235 236 size.left = -width / 2; 237 size.right = width / 2; 238 dialog.size = size; 239 240 initDiplomacy = () => {}; 241 } 242 230 243 function openDiplomacy() 231 244 { 232 245 closeOpenDialogs(); 246 initDiplomacy(); 233 247 234 248 if (g_ViewedPlayer < 1) 235 249 return; … … function openDiplomacy() 254 268 diplomacyFormatTributeButtons(i, myself || playerInactive); 255 269 diplomacyFormatAttackRequestButton(i, myself || playerInactive || isCeasefireActive || !hasAllies || !g_Players[i].isEnemy[g_ViewedPlayer]); 256 270 } 257 258 271 Engine.GetGUIObjectByName("diplomacyDialogPanel").hidden = false; 259 272 } 260 273 … … function diplomacyFormatStanceButtons(i, hidden) 305 318 306 319 function diplomacyFormatTributeButtons(i, hidden) 307 320 { 308 for (let resource of RESOURCES) 321 let resNames = g_ResourceData.GetNames(); 322 let resCodes = g_ResourceData.GetCodes(); 323 let r = 0; 324 for (let resCode of resCodes) 309 325 { 310 let button = Engine.GetGUIObjectByName("diplomacyPlayerTribute"+resource[0].toUpperCase()+resource.substring(1)+"["+(i-1)+"]"); 326 let button = Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]_tribute["+r+"]"); 327 if (!button) 328 break; 329 Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]_tribute["+r+"]_image").sprite = "stretched:session/icons/resources/"+resCode+".png"; 311 330 button.hidden = hidden; 331 setPanelObjectPosition(button, r, 8, 0); 332 ++r; 312 333 if (hidden) 313 334 continue; 314 335 315 336 button.enabled = controlsPlayer(g_ViewedPlayer); 316 button.tooltip = formatTributeTooltip(i, res ource, 100);317 button.onpress = (function(i, res ource, button) {337 button.tooltip = formatTributeTooltip(i, resNames[resCode], 100); 338 button.onpress = (function(i, resCode, button) { 318 339 // Shift+click to send 500, shift+click+click to send 1000, etc. 319 340 // See INPUT_MASSTRIBUTING in input.js 320 341 let multiplier = 1; … … function diplomacyFormatTributeButtons(i, hidden) 327 348 } 328 349 329 350 let amounts = {}; 330 for (let type of RESOURCES)331 amounts[ type] = 0;332 amounts[res ource] = 100 * multiplier;351 for (let res of resCodes) 352 amounts[res] = 0; 353 amounts[resCode] = 100 * multiplier, 333 354 334 button.tooltip = formatTributeTooltip(i, res ource, amounts[resource]);355 button.tooltip = formatTributeTooltip(i, resNames[resCode], amounts[resCode]); 335 356 336 357 // This is in a closure so that we have access to `player`, `amounts`, and `multiplier` without some 337 358 // evil global variable hackery. 338 359 g_FlushTributing = function() { 339 360 Engine.PostNetworkCommand({ "type": "tribute", "player": i, "amounts": amounts }); 340 361 multiplier = 1; 341 button.tooltip = formatTributeTooltip(i, res ource, 100);362 button.tooltip = formatTributeTooltip(i, resNames[resCode], 100); 342 363 }; 343 364 344 365 if (!isBatchTrainPressed) 345 366 g_FlushTributing(); 346 367 }; 347 })(i, res ource, button);368 })(i, resCode, button); 348 369 } 349 370 } 350 371 … … function toggleDiplomacy() 377 398 openDiplomacy(); 378 399 } 379 400 401 function initTrade() 402 { 403 let dialog = Engine.GetGUIObjectByName("tradeDialogPanel"); 404 let size = dialog.size; 405 let width = size.right - size.left; 406 407 let tradeSize = Engine.GetGUIObjectByName("tradeResource[0]").size; 408 width += g_ResourceData.GetCodes().length * (tradeSize.right - tradeSize.left); 409 410 size.left = -width / 2; 411 size.right = width / 2; 412 dialog.size = size; 413 414 initTrade = () => {}; 415 } 416 380 417 function openTrade() 381 418 { 382 419 closeOpenDialogs(); 420 initTrade(); 383 421 384 422 if (g_ViewedPlayer < 1) 385 423 return; … … function openTrade() 388 426 389 427 var updateButtons = function() 390 428 { 391 for ( varres in button)429 for (let res in button) 392 430 { 393 431 button[res].label.caption = proba[res] + "%"; 394 432 … … function openTrade() 398 436 } 399 437 }; 400 438 401 var proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer); 402 var button = {}; 403 var selec = RESOURCES[0]; 404 for (var i = 0; i < RESOURCES.length; ++i) 405 { 406 var buttonResource = Engine.GetGUIObjectByName("tradeResource["+i+"]"); 407 if (i > 0) 408 { 409 var size = Engine.GetGUIObjectByName("tradeResource["+(i-1)+"]").size; 410 var width = size.right - size.left; 411 size.left += width; 412 size.right += width; 413 Engine.GetGUIObjectByName("tradeResource["+i+"]").size = size; 414 } 415 var resource = RESOURCES[i]; 416 proba[resource] = (proba[resource] ? proba[resource] : 0); 417 var buttonResource = Engine.GetGUIObjectByName("tradeResourceButton["+i+"]"); 418 var icon = Engine.GetGUIObjectByName("tradeResourceIcon["+i+"]"); 419 icon.sprite = "stretched:session/icons/resources/" + resource + ".png"; 420 var label = Engine.GetGUIObjectByName("tradeResourceText["+i+"]"); 421 var buttonUp = Engine.GetGUIObjectByName("tradeArrowUp["+i+"]"); 422 var buttonDn = Engine.GetGUIObjectByName("tradeArrowDn["+i+"]"); 423 var iconSel = Engine.GetGUIObjectByName("tradeResourceSelection["+i+"]"); 424 button[resource] = { "up": buttonUp, "dn": buttonDn, "label": label, "sel": iconSel }; 439 let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer); 440 let button = {}; 441 let resCodes = g_ResourceData.GetCodes(); 442 let selec = resCodes[0]; 443 hideRemaining("tradeResources", resCodes.length); 444 Engine.GetGUIObjectByName("tradeHelp").hidden = false; 425 445 446 for (let i = 0; i < resCodes.length; ++i) 447 { 448 if (!Engine.GetGUIObjectByName("tradeResource["+i+"]")) 449 break; 450 setPanelObjectPosition(Engine.GetGUIObjectByName("tradeResource["+i+"]"), i, 8); 451 let resCode = resCodes[i]; 452 proba[resCode] = proba[resCode] || 0; 453 let icon = Engine.GetGUIObjectByName("tradeResourceIcon["+i+"]"); 454 icon.sprite = "stretched:session/icons/resources/" + resCode + ".png"; 455 let label = Engine.GetGUIObjectByName("tradeResourceText["+i+"]"); 456 let buttonUp = Engine.GetGUIObjectByName("tradeArrowUp["+i+"]"); 457 let buttonDn = Engine.GetGUIObjectByName("tradeArrowDn["+i+"]"); 458 let iconSel = Engine.GetGUIObjectByName("tradeResourceSelection["+i+"]"); 459 button[resCode] = { "up": buttonUp, "dn": buttonDn, "label": label, "sel": iconSel }; 460 461 let buttonResource = Engine.GetGUIObjectByName("tradeResourceButton["+i+"]"); 426 462 buttonResource.enabled = controlsPlayer(g_ViewedPlayer); 427 463 buttonResource.onpress = (function(resource){ 428 464 return function() { 429 465 if (Engine.HotkeyIsPressed("session.fulltradeswap")) 430 466 { 431 for ( var ress of RESOURCES)432 proba[res s] = 0;467 for (let res of resCodes) 468 proba[res] = 0; 433 469 proba[resource] = 100; 434 470 Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); 435 471 } 436 472 selec = resource; 437 473 updateButtons(); 438 474 }; 439 })(res ource);475 })(resCode); 440 476 441 477 buttonUp.enabled = controlsPlayer(g_ViewedPlayer); 442 478 buttonUp.onpress = (function(resource){ … … function openTrade() 446 482 Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); 447 483 updateButtons(); 448 484 }; 449 })(res ource);485 })(resCode); 450 486 451 487 buttonDn.enabled = controlsPlayer(g_ViewedPlayer); 452 488 buttonDn.onpress = (function(resource){ … … function openTrade() 456 492 Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); 457 493 updateButtons(); 458 494 }; 459 })(res ource);495 })(resCode); 460 496 } 461 497 updateButtons(); 462 498 463 499 let traderNumber = Engine.GuiInterfaceCall("GetTraderNumber", g_ViewedPlayer); 464 500 Engine.GetGUIObjectByName("landTraders").caption = getIdleLandTradersText(traderNumber); 465 501 Engine.GetGUIObjectByName("shipTraders").caption = getIdleShipTradersText(traderNumber); 466 467 502 Engine.GetGUIObjectByName("tradeDialogPanel").hidden = false; 468 503 } 469 504 -
binaries/data/mods/public/gui/session/selection_details.js
diff --git a/binaries/data/mods/public/gui/session/selection_details.js b/binaries/data/mods/public/gui/session/selection_details.js index 29acc09..36fa2a6 100644
a b function layoutSelectionMultiple() 13 13 function getResourceTypeDisplayName(resourceType) 14 14 { 15 15 let resourceCode = resourceType.generic; 16 if (resourceCode == "treasure") 17 return getLocalizedResourceName(resourceType.specific, "firstWord"); 18 else 19 return getLocalizedResourceName(resourceCode, "firstWord"); 16 let resourceName = g_ResourceData.GetNames()[(resourceCode == "treasure" ? resourceType.specific : resourceCode)] 17 return getLocalizedResourceName(resourceName, "firstWord"); 20 18 } 21 19 22 20 // Updates the health bar of garrisoned units -
binaries/data/mods/public/gui/session/selection_panels.js
diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js index c21fc4f..ceae7a9 100644
a b let g_FormationsInfo = new Map(); 34 34 35 35 let g_SelectionPanels = {}; 36 36 37 let g_BarterSell; 38 37 39 g_SelectionPanels.Alert = { 38 40 "getMaxNumberOfItems": function() 39 41 { … … g_SelectionPanels.Alert = { 87 89 g_SelectionPanels.Barter = { 88 90 "getMaxNumberOfItems": function() 89 91 { 90 return 4;92 return 8; 91 93 }, 92 94 "rowLength": 4, 93 95 "getItems": function(unitEntState, selection) 94 96 { 95 97 if (!unitEntState.barterMarket) 96 98 return []; 97 // ["food", "wood", "stone", "metal"] 98 return BARTER_RESOURCES; 99 return g_ResourceData.GetCodes(); 99 100 }, 100 101 "setupButton": function(data) 101 102 { … … g_SelectionPanels.Barter = { 115 116 if (Engine.HotkeyIsPressed("session.massbarter")) 116 117 amountToSell *= BARTER_BUNCH_MULTIPLIER; 117 118 119 if (!g_BarterSell) 120 g_BarterSell = g_ResourceData.GetCodes()[0]; 121 118 122 amount.Sell.caption = "-" + amountToSell; 119 123 let prices = data.unitEntState.barterMarket.prices; 120 124 amount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[data.item] * amountToSell); 121 125 122 let resource = getLocalizedResourceName( data.item, "withinSentence");126 let resource = getLocalizedResourceName(g_ResourceData.GetNames()[data.item], "firstWord"); 123 127 button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource }); 124 128 button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource }); 125 129 … … g_SelectionPanels.Barter = { 164 168 button.Sell.hidden = false; 165 169 selectionIcon.hidden = !isSelected; 166 170 167 setPanelObjectPosition(button.Sell, data.i, data.rowLength); 168 setPanelObjectPosition(button.Buy, data.i + data.rowLength, data.rowLength); 171 let sellPos = data.i + (data.i >= data.rowLength ? data.rowLength : 0); 172 let buyPos = data.i + data.rowLength * (data.i >= data.rowLength ? 2 : 1); 173 setPanelObjectPosition(button.Sell, sellPos, data.rowLength); 174 setPanelObjectPosition(button.Buy, buyPos, data.rowLength); 169 175 return true; 170 176 } 171 177 }; -
binaries/data/mods/public/gui/session/selection_panels_helpers.js
diff --git a/binaries/data/mods/public/gui/session/selection_panels_helpers.js b/binaries/data/mods/public/gui/session/selection_panels_helpers.js index fc0e7a6..46976f9 100644
a b 1 1 const BARTER_RESOURCE_AMOUNT_TO_SELL = 100; 2 2 const BARTER_BUNCH_MULTIPLIER = 5; 3 const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];4 3 const BARTER_ACTIONS = ["Sell", "Buy"]; 5 4 const GATE_ACTIONS = ["lock", "unlock"]; 6 5 7 // upgrade constants8 6 const UPGRADING_NOT_STARTED = -2; 9 7 const UPGRADING_CHOSEN_OTHER = -1; 10 8 11 // ==============================================12 // BARTER HELPERS13 // Resources to sell on barter panel14 var g_BarterSell = "food";15 16 9 function canMoveSelectionIntoFormation(formationTemplate) 17 10 { 18 11 if (!(formationTemplate in g_canMoveIntoFormation)) -
binaries/data/mods/public/gui/session/selection_panels_left/barter_panel.xml
diff --git a/binaries/data/mods/public/gui/session/selection_panels_left/barter_panel.xml b/binaries/data/mods/public/gui/session/selection_panels_left/barter_panel.xml index f32e117..717efce 100644
a b 1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <object name="unitBarterPanel" 3 size=" 6 36100% 100%"3 size="24 12 100% 100%" 4 4 hidden="true" 5 5 > 6 <object ghost="true" style="resourceText" type="text" size="0 0 100% 20"> 7 <translatableAttribute id="tooltip">Exchange resources:</translatableAttribute>8 </object> 9 <object size="0 32 100% 124">10 < repeat count="4">11 < !-- sell -->12 <object name="unitBarterSell Button[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">13 <object name="unitBarterSellIcon[n]" type="image" ghost="true" size="3 3 43 43"/>14 <object name="unitBarterSellAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>15 <object name="unitBarterSellSelection[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/corners.png"/> 16 </object>17 <!-- buy -->18 <object name="unitBarterBuy Button[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">19 <object name="unitBarterBuyIcon[n]" type="image" ghost="true" size="3 3 43 43"/>20 <object name="unitBarterBuyAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>21 </object> 22 23 </object> 6 7 <repeat count="8"> 8 9 <!-- Sell --> 10 <object name="unitBarterSellButton[n]" style="iconButton" type="button" size="0 0 36 36" tooltip_style="sessionToolTipBottomBold" hidden="true"> 11 <object name="unitBarterSellIcon[n]" type="image" ghost="true" size="3 3 33 33"/> 12 <object name="unitBarterSellAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/> 13 <object name="unitBarterSellSelection[n]" hidden="true" type="image" ghost="true" size="3 3 33 33" sprite="stretched:session/icons/corners.png"/> 14 </object> 15 16 <!-- Buy --> 17 <object name="unitBarterBuyButton[n]" style="iconButton" type="button" size="0 0 36 36" tooltip_style="sessionToolTipBottomBold" hidden="true"> 18 <object name="unitBarterBuyIcon[n]" type="image" ghost="true" size="3 3 33 33"/> 19 <object name="unitBarterBuyAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/> 20 </object> 21 22 </repeat> 23 24 24 </object> -
binaries/data/mods/public/gui/session/session.js
diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js index 35af7a7..22a41b6 100644
a b var g_EntityStates = {}; 122 122 var g_TemplateData = {}; 123 123 var g_TemplateDataWithoutLocalization = {}; 124 124 var g_TechnologyData = {}; 125 var g_ResourceData = new Resources(); 125 126 126 127 /** 127 128 * Top coordinate of the research list. … … function updateTopPanel() 463 464 let viewPlayer = Engine.GetGUIObjectByName("viewPlayer"); 464 465 viewPlayer.hidden = !g_IsObserver && !g_DevSettings.changePerspective; 465 466 466 Engine.GetGUIObjectByName("food").hidden = !isPlayer; 467 Engine.GetGUIObjectByName("wood").hidden = !isPlayer; 468 Engine.GetGUIObjectByName("stone").hidden = !isPlayer; 469 Engine.GetGUIObjectByName("metal").hidden = !isPlayer; 467 let resCodes = g_ResourceData.GetCodes(); 468 let resNames = g_ResourceData.GetNames(); 469 let r = 0; 470 for (let res of resCodes) 471 { 472 if (!Engine.GetGUIObjectByName("resource["+r+"]")) 473 { 474 warn("Current GUI limits prevent displaying more than eight (8) resources"); 475 break; 476 } 477 Engine.GetGUIObjectByName("resource["+r+"]_icon").sprite = "stretched:session/icons/resources/" + res + ".png"; 478 Engine.GetGUIObjectByName("resource["+r+"]").hidden = !isPlayer; 479 ++r; 480 } 481 horizontallyDistributeObjects("resourceCounts", 0, r); 482 hideRemaining("resourceCounts", r); 483 470 484 Engine.GetGUIObjectByName("population").hidden = !isPlayer; 471 485 Engine.GetGUIObjectByName("diplomacyButton1").hidden = !isPlayer; 472 486 Engine.GetGUIObjectByName("tradeButton1").hidden = !isPlayer; … … function leaveGame(willRejoin) 547 561 "disconnected": g_Disconnected, 548 562 "isReplay": g_IsReplay, 549 563 "replayDirectory": !g_HasRejoined && replayDirectory, 550 "replaySelectionData": g_ReplaySelectionData 564 "replaySelectionData": g_ReplaySelectionData, 565 "resources": GetSimState().resources 551 566 } 552 567 }); 553 568 } … … function getAllyStatTooltip(resource) 947 962 948 963 function updatePlayerDisplay() 949 964 { 950 let playerState = GetSimState().players[g_ViewedPlayer]; 965 let simState = GetSimState(); 966 let playerState = simState.players[g_ViewedPlayer]; 951 967 if (!playerState) 952 968 return; 953 969 954 for (let res of RESOURCES) 970 let resCodes = g_ResourceData.GetCodes(); 971 let resNames = g_ResourceData.GetNames(); 972 for (let r = 0; r < resCodes.length; ++r) 955 973 { 956 Engine.GetGUIObjectByName("resource_" + res).caption = Math.floor(playerState.resourceCounts[res]); 957 Engine.GetGUIObjectByName(res).tooltip = getLocalizedResourceName(res, "firstWord") + getAllyStatTooltip(res); 974 if (!Engine.GetGUIObjectByName("resource["+r+"]")) 975 break; 976 let res = resCodes[r]; 977 Engine.GetGUIObjectByName("resource["+r+"]").tooltip = getLocalizedResourceName(resNames[res], "firstWord") + getAllyStatTooltip(res); 978 Engine.GetGUIObjectByName("resource["+r+"]_count").caption = Math.floor(playerState.resourceCounts[res]); 958 979 } 959 980 960 981 Engine.GetGUIObjectByName("resourcePop").caption = sprintf(translate("%(popCount)s/%(popLimit)s"), playerState); -
deleted file binaries/data/mods/public/gui/session/top_panel/resource_food.xml
diff --git a/binaries/data/mods/public/gui/session/top_panel/resource_food.xml b/binaries/data/mods/public/gui/session/top_panel/resource_food.xml deleted file mode 100644 index 4d84ca7..0000000
+ - 1 <?xml version="1.0" encoding="utf-8"?>2 <object name="food" size="10 0 100 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">3 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/food.png" ghost="true"/>4 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_food"/>5 </object> -
deleted file binaries/data/mods/public/gui/session/top_panel/resource_metal.xml
diff --git a/binaries/data/mods/public/gui/session/top_panel/resource_metal.xml b/binaries/data/mods/public/gui/session/top_panel/resource_metal.xml deleted file mode 100644 index 4edba79..0000000
+ - 1 <?xml version="1.0" encoding="utf-8"?>2 <object name="metal" size="280 0 370 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">3 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/metal.png" ghost="true"/>4 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_metal"/>5 </object> -
binaries/data/mods/public/gui/session/top_panel/resource_population.xml
diff --git a/binaries/data/mods/public/gui/session/top_panel/resource_population.xml b/binaries/data/mods/public/gui/session/top_panel/resource_population.xml index 9c9dcc2..9d66e40 100644
a b 1 1 <?xml version="1.0" encoding="utf-8"?> 2 <object name="population" size=" 370 0 460100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">2 <object name="population" size="50%-90-52 0 50%-52 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold"> 3 3 <object size="0 -4 40 34" type="image" sprite="stretched:session/icons/resources/population.png" ghost="true"/> 4 4 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourcePop"/> 5 5 </object> -
deleted file binaries/data/mods/public/gui/session/top_panel/resource_stone.xml
diff --git a/binaries/data/mods/public/gui/session/top_panel/resource_stone.xml b/binaries/data/mods/public/gui/session/top_panel/resource_stone.xml deleted file mode 100644 index 6133acc..0000000
+ - 1 <?xml version="1.0" encoding="utf-8"?>2 <object name="stone" size="190 0 280 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">3 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/stone.png" ghost="true"/>4 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_stone"/>5 </object> -
deleted file binaries/data/mods/public/gui/session/top_panel/resource_wood.xml
diff --git a/binaries/data/mods/public/gui/session/top_panel/resource_wood.xml b/binaries/data/mods/public/gui/session/top_panel/resource_wood.xml deleted file mode 100644 index f020979..0000000
+ - 1 <?xml version="1.0" encoding="utf-8"?>2 <object name="wood" size="100 0 190 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold">3 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/wood.png" ghost="true"/>4 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource_wood"/>5 </object> -
new file inaries/data/mods/public/gui/session/top_panel/resources.xml
diff --git a/binaries/data/mods/public/gui/session/top_panel/resources.xml b/binaries/data/mods/public/gui/session/top_panel/resources.xml new file mode 100644 index 0000000..520aa35
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 3 <object size="10 0 50%-90-52 100%" name="resourceCounts"> 4 <repeat count="8"> 5 <object name="resource[n]" size="0 0 90 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold"> 6 <object size="0 -4 40 36" type="image" name="resource[n]_icon" ghost="true"/> 7 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resource[n]_count"/> 8 </object> 9 </repeat> 10 </object> -
binaries/data/mods/public/gui/session/trade_window.xml
diff --git a/binaries/data/mods/public/gui/session/trade_window.xml b/binaries/data/mods/public/gui/session/trade_window.xml index 80b226c..4e1e5e0 100644
a b 1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <object name="tradeDialogPanel" 3 size="50%- 250 50%-130 50%+25050%+100"3 size="50%-134 50%-130 50%+134 50%+100" 4 4 type="image" 5 5 hidden="true" 6 6 sprite="ModernDialog" … … 15 15 <translatableAttribute id="caption">Trading goods selection:</translatableAttribute> 16 16 </object> 17 17 18 <object size="180 0 100% 100%" >19 <repeat count=" 4">18 <object size="180 0 100% 100%" name="tradeResources"> 19 <repeat count="8"> 20 20 <object name="tradeResource[n]" size="0 0 58 32"> 21 21 <object name="tradeResourceButton[n]" size="4 0 36 100%" type="button" style="StoneButton"> 22 22 <object name="tradeResourceIcon[n]" type="image" ghost="true"/> -
binaries/data/mods/public/gui/structree/draw.js
diff --git a/binaries/data/mods/public/gui/structree/draw.js b/binaries/data/mods/public/gui/structree/draw.js index 92c60ce..c81f1e5 100644
a b function draw() 112 112 if (p>c) 113 113 c = p; 114 114 115 hideRemaining("phase["+i+"]_struct["+s+"]_row["+r+"] _prod[", p, "]");115 hideRemaining("phase["+i+"]_struct["+s+"]_row["+r+"]", p); 116 116 } 117 117 118 118 let size = thisEle.size; … … function draw() 132 132 phaEle.size = size; 133 133 } 134 134 ++r; 135 hideRemaining("phase["+i+"]_struct["+s+"]_row [", r, "]");135 hideRemaining("phase["+i+"]_struct["+s+"]_rows", r); 136 136 ++s; 137 137 } 138 hideRemaining("phase["+i+"] _struct[", s, "]");138 hideRemaining("phase["+i+"]", s); 139 139 ++i; 140 140 } 141 141 … … function draw() 179 179 ++p; 180 180 } 181 181 } 182 hideRemaining("trainer["+t+"]_ prod[", p, "]");182 hideRemaining("trainer["+t+"]_row", p); 183 183 184 184 let size = thisEle.size; 185 185 size.right = size.left + Math.max(p*24, defWidth) + 4; … … function draw() 193 193 phaEle.size = size; 194 194 ++t; 195 195 } 196 hideRemaining("trainer [", t, "]");196 hideRemaining("trainers", t); 197 197 198 198 let size = Engine.GetGUIObjectByName("display_tree").size; 199 199 size.right = t > 0 ? -124 : -4; … … function getPositionOffset(idx) 235 235 return size; 236 236 } 237 237 238 function hideRemaining(prefix, idx, suffix)239 {240 let obj = Engine.GetGUIObjectByName(prefix + idx + suffix);241 while (obj)242 {243 obj.hidden = true;244 ++idx;245 obj = Engine.GetGUIObjectByName(prefix + idx + suffix);246 }247 }248 249 250 238 /** 251 239 * Positions certain elements that only need to be positioned once 252 240 * (as <repeat> does not reposition automatically). … … function predraw() 283 271 prodBarIcon.sprite = "stretched:session/portraits/"+g_ParsedData.phases[phaseList[i+j]].icon; 284 272 } 285 273 // Hide remaining prod bars 286 hideRemaining("phase["+i+"]_bar [", j-1, "]");274 hideRemaining("phase["+i+"]_bars", j-1); 287 275 288 276 let s = 0; 289 277 let ele = Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]"); … … function predraw() 334 322 g_DrawLimits[pha].structQuant = s; 335 323 ++i; 336 324 } 337 hideRemaining("phase [", i, "]");338 hideRemaining("phase [", i, "]_bar");339 325 hideRemaining("phase_rows", i); 326 hideRemaining("phase_ident", i); 327 340 328 let t = 0; 341 329 let ele = Engine.GetGUIObjectByName("trainer["+t+"]"); 342 330 g_DrawLimits.trainer = { -
binaries/data/mods/public/gui/structree/load.js
diff --git a/binaries/data/mods/public/gui/structree/load.js b/binaries/data/mods/public/gui/structree/load.js index 534747b..dfeb24a 100644
a b 5 5 */ 6 6 function getGatherRates(templateName) 7 7 { 8 // TODO: It would be nice to use the gather rates present in the templates 9 // instead of hard-coding the possible rates here. 10 11 // We ignore ruins here, as those are not that common and would skew the results 12 var types = { 13 "food": ["food", "food.fish", "food.fruit", "food.grain", "food.meat", "food.milk"], 14 "wood": ["wood", "wood.tree"], 15 "stone": ["stone", "stone.rock"], 16 "metal": ["metal", "metal.ore"] 17 }; 18 var rates = {}; 8 let rates = {}; 19 9 20 for (let type in types)10 for (let resource of g_ResourceData.GetData()) 21 11 { 12 let types = [resource.code]; 13 for (let subtype of resource.subtypes) 14 // We ignore ruins as those are not that common and skew the results 15 if (subtype !== "ruins") 16 types.push(resource.code + "." + subtype); 17 22 18 let count, rate; 23 [rate, count] = types [type].reduce(function(sum, t){19 [rate, count] = types.reduce((sum, t) => { 24 20 let r = +fetchValue(templateName, "ResourceGatherer/Rates/"+t); 25 21 return [sum[0] + (r > 0 ? r : 0), sum[1] + (r > 0 ? 1 : 0)]; 26 22 }, [0, 0]); 27 23 28 24 if (rate > 0) 29 rates[ type] = Math.round(rate / count * 100) / 100;25 rates[resource.code] = +(rate / count).toFixed(1); 30 26 } 31 27 32 28 if (!Object.keys(rates).length) -
binaries/data/mods/public/gui/structree/rows.xml
diff --git a/binaries/data/mods/public/gui/structree/rows.xml b/binaries/data/mods/public/gui/structree/rows.xml index f6d700f..fdffe3c 100644
a b 9 9 <object type="image" style="StructIcon" name="phase[k]_struct[s]_icon" 10 10 sprite="stretched:pregame/shell/logo/wfg_logo_white.png" 11 11 /> 12 <repeat count="4" var="r"> 13 <object name="phase[k]_struct[s]_row[r]"> 14 <repeat count="24" var="p"> 15 <object type="image" style="ProdBox" name="phase[k]_struct[s]_row[r]_prod[p]"/> 16 </repeat> 17 </object> 18 </repeat> 19 </object> 12 <object name="phase[k]_struct[s]_rows"> 13 <repeat count="4" var="r"> 14 <object name="phase[k]_struct[s]_row[r]"> 15 <repeat count="24" var="p"> 16 <object type="image" style="ProdBox" name="phase[k]_struct[s]_row[r]_prod[p]"/> 17 </repeat> 18 </object> 19 </repeat> 20 </object> 21 </object> 20 22 </repeat> 21 23 </object> 22 24 </repeat> -
binaries/data/mods/public/gui/structree/structree.js
diff --git a/binaries/data/mods/public/gui/structree/structree.js b/binaries/data/mods/public/gui/structree/structree.js index 65bfd9e..fcb6a9c 100644
a b var g_Lists = {}; 9 9 var g_CivData = {}; 10 10 var g_SelectedCiv = ""; 11 11 var g_CallbackSet = false; 12 var g_ResourceData = new Resources(); 12 13 13 14 /** 14 15 * Initialize the dropdown containing all the available civs -
binaries/data/mods/public/gui/structree/structree.xml
diff --git a/binaries/data/mods/public/gui/structree/structree.xml b/binaries/data/mods/public/gui/structree/structree.xml index 4165e1c..2e35b38 100644
a b 63 63 64 64 <!-- Structure Tree display --> 65 65 <object size="0 54+64 100%-124 100%-54" name="display_tree"> 66 <repeat count="4" var="n"> 67 <object name="phase[n]_phase" type="image"/> 68 <object name="phase[n]_bar"> 69 <repeat count="4" var="k"> 70 <object name="phase[n]_bar[k]" type="image" sprite="ProdBar"> 71 <object name="phase[n]_bar[k]_icon" type="image" size="2 2 20 20"/> 66 <object name="phase_ident"> 67 <repeat count="4" var="n"> 68 <object> 69 <object name="phase[n]_phase" type="image"/> 70 <object name="phase[n]_bars"> 71 <repeat count="4" var="k"> 72 <object name="phase[n]_bar[k]" type="image" sprite="ProdBar"> 73 <object name="phase[n]_bar[k]_icon" type="image" size="2 2 20 20"/> 74 </object> 75 </repeat> 72 76 </object> 73 </ repeat>74 </ object>75 </ repeat>77 </object> 78 </repeat> 79 </object> 76 80 77 81 <object type="image" style="TreeDisplay" size="48+16+8 0 100%-12 100%"> 78 82 <include file="gui/structree/rows.xml"/> … … 92 96 <translatableAttribute id="caption">Trainer Units</translatableAttribute> 93 97 </object> 94 98 95 <object type="image" style="TreeDisplay" size="0 24 100% 100%" >99 <object type="image" style="TreeDisplay" size="0 24 100% 100%" name="trainers"> 96 100 <repeat count="3" var="t"> 97 101 <object type="image" style="StructBox" name="trainer[t]"> 98 102 <object type="text" style="StructNameSpecific" name="trainer[t]_name"/> -
binaries/data/mods/public/gui/summary/counters.js
diff --git a/binaries/data/mods/public/gui/summary/counters.js b/binaries/data/mods/public/gui/summary/counters.js index 562e3bb..36b1812 100644
a b function updateCountersPlayer(playerState, counters, idGUI) 63 63 { 64 64 for (let w in counters) 65 65 { 66 if (!Engine.GetGUIObjectByName(idGUI + "[" + w + "]")) 67 break; 66 68 let fn = counters[w].fn; 67 69 Engine.GetGUIObjectByName(idGUI + "[" + w + "]").caption = fn && fn(playerState, w); 68 70 } … … function calculateUnits(playerState, position) 250 252 251 253 function calculateResources(playerState, position) 252 254 { 253 let type = g_Resource sTypes[position];255 let type = g_ResourceData.GetCodes()[position]; 254 256 255 257 return formatIncome( 256 258 playerState.statistics.resourcesGathered[type], … … function calculateTotalResources(playerState) 262 264 let totalGathered = 0; 263 265 let totalUsed = 0; 264 266 265 for (let type of g_Resource sTypes)267 for (let type of g_ResourceData.GetCodes()) 266 268 { 267 269 totalGathered += playerState.statistics.resourcesGathered[type]; 268 270 totalUsed += playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type]; … … function calculateResourcesTeam(counters) 330 332 331 333 function calculateResourceExchanged(playerState, position) 332 334 { 333 let type = g_Resource sTypes[position];335 let type = g_ResourceData.GetCodes()[position]; 334 336 335 337 return formatIncome( 336 338 playerState.statistics.resourcesBought[type], -
binaries/data/mods/public/gui/summary/layout.js
diff --git a/binaries/data/mods/public/gui/summary/layout.js b/binaries/data/mods/public/gui/summary/layout.js index 7feeb45..efb20e9 100644
a b var g_ScorePanelsData = { 92 92 "resources": { 93 93 "headings": [ 94 94 { "caption": translate("Player name"), "yStart": 26, "width": 200 }, 95 { "caption": translate("Food"), "yStart": 34, "width": 100 },96 { "caption": translate("Wood"), "yStart": 34, "width": 100 },97 { "caption": translate("Stone"), "yStart": 34, "width": 100 },98 { "caption": translate("Metal"), "yStart": 34, "width": 100 },99 95 { "caption": translate("Total"), "yStart": 34, "width": 110 }, 100 96 { 101 97 "caption": sprintf(translate("Tributes \n(%(sent)s / %(received)s)"), … … var g_ScorePanelsData = { 121 117 }, // width = 510 122 118 ], 123 119 "counters": [ 124 { "width": 100, "fn": calculateResources, "verticalOffset": 12 },125 { "width": 100, "fn": calculateResources, "verticalOffset": 12 },126 { "width": 100, "fn": calculateResources, "verticalOffset": 12 },127 { "width": 100, "fn": calculateResources, "verticalOffset": 12 },128 120 { "width": 110, "fn": calculateTotalResources, "verticalOffset": 12 }, 129 121 { "width": 121, "fn": calculateTributeSent, "verticalOffset": 12 }, 130 122 { "width": 100, "fn": calculateTreasureCollected, "verticalOffset": 12 }, … … var g_ScorePanelsData = { 135 127 "market": { 136 128 "headings": [ 137 129 { "caption": translate("Player name"), "yStart": 26, "width": 200 }, 138 { "caption": translate("Food exchanged"), "yStart": 16, "width": 100 },139 { "caption": translate("Wood exchanged"), "yStart": 16, "width": 100 },140 { "caption": translate("Stone exchanged"), "yStart": 16, "width": 100 },141 { "caption": translate("Metal exchanged"), "yStart": 16, "width": 100 },142 130 { "caption": translate("Barter efficiency"), "yStart": 16, "width": 100 }, 143 131 { "caption": translate("Trade income"), "yStart": 16, "width": 100 } 144 132 ], 145 133 "titleHeadings": [], 146 134 "counters": [ 147 { "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },148 { "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },149 { "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },150 { "width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12 },151 135 { "width": 100, "fn": calculateBarterEfficiency, "verticalOffset": 12 }, 152 136 { "width": 100, "fn": calculateTradeIncome, "verticalOffset": 12 } 153 137 ], … … function updateGeneralPanelHeadings(headings) 206 190 headerGUIName = "Heading[" + (h - 1) + "]"; 207 191 208 192 let headerGUI = Engine.GetGUIObjectByName(headerGUIName); 193 if (!headerGUI) 194 break; 209 195 headerGUI.caption = headings[h].caption; 210 196 headerGUI.size = left + " " + headings[h].yStart + " " + (left + headings[h].width) + " 100%"; 211 197 headerGUI.hidden = false; … … function updateGeneralPanelCounter(counters) 249 235 for (let w in counters) 250 236 { 251 237 counterObject = Engine.GetGUIObjectByName("valueData[" + p + "][" + w + "]"); 238 if (!counterObject) 239 break; 252 240 counterObject.size = left + " " + counters[w].verticalOffset + " " + (left + counters[w].width) + " 100%"; 253 241 counterObject.hidden = false; 254 242 left += counters[w].width; … … function updateGeneralPanelCounter(counters) 264 252 for (let w in counters) 265 253 { 266 254 counterObject = Engine.GetGUIObjectByName("valueDataTeam[" + t + "][" + p + "][" + w + "]"); 255 if (!counterObject) 256 break; 267 257 counterObject.size = left + " " + counters[w].verticalOffset + " " + (left + counters[w].width) + " 100%"; 268 258 counterObject.hidden = false; 269 259 -
binaries/data/mods/public/gui/summary/summary.js
diff --git a/binaries/data/mods/public/gui/summary/summary.js b/binaries/data/mods/public/gui/summary/summary.js index 51e5577..7849b1f 100644
a b 1 const g_MaxHeadingTitle= 8;1 const g_MaxHeadingTitle= 12; 2 2 3 3 // const for filtering long collective headings 4 4 const g_LongHeadingWidth = 250; … … const g_CapturedColor = '[color="255 255 157"]'; 17 17 18 18 const g_BuildingsTypes = [ "total", "House", "Economic", "Outpost", "Military", "Fortress", "CivCentre", "Wonder" ]; 19 19 const g_UnitsTypes = [ "total", "Infantry", "Worker", "Cavalry", "Champion", "Hero", "Ship", "Trader" ]; 20 const g_ResourcesTypes = [ "food", "wood", "stone", "metal" ];21 20 22 21 // Colors used for gathered and traded resources 23 22 const g_IncomeColor = '[color="201 255 200"]'; … … var g_PlayerCount = 0; 34 33 // Count players without team (or all if teams are not displayed) 35 34 var g_WithoutTeam = 0; 36 35 var g_GameData; 36 var g_ResourceData = new Resources(); 37 37 38 38 function selectPanel(panel) 39 39 { … … function init(data) 242 242 else 243 243 g_Teams = false; 244 244 245 // Resource names and counters 246 let resHeads = []; 247 let tradeHeads = []; 248 let resPanel = g_ScorePanelsData.resources; 249 let tradePanel = g_ScorePanelsData.market; 250 let resNames = g_ResourceData.GetNames(); 251 let resCodes = g_ResourceData.GetCodes(); 252 for (let code of resCodes) 253 { 254 resHeads.push({ 255 "caption": translateWithContext("firstWord", resNames[code]), 256 "yStart": 34, 257 "width": 100 258 }); 259 260 resPanel.counters.unshift({ 261 "width": 100, 262 "fn": calculateResources, 263 "verticalOffset": 12 264 }); 265 266 tradeHeads.push({ 267 "caption": sprintf( 268 translate("%(resource)s exchanged"), { 269 "resource": translateWithContext("withinSentence", resNames[code]) 270 }), 271 "yStart": 16, 272 "width": 100 273 }); 274 275 tradePanel.counters.unshift({ 276 "width": 100, 277 "fn": calculateResourceExchanged, 278 "verticalOffset": 12 279 }); 280 } 281 resPanel.headings.splice.apply(resPanel.headings, [1, 0].concat(resHeads)); 282 resPanel.titleHeadings[0].width = 100 * resCodes.length + 110; 283 tradePanel.headings.splice.apply(tradePanel.headings, [1, 0].concat(tradeHeads)); 284 245 285 // Erase teams data if teams are not displayed 246 286 if (!g_Teams) 247 287 { -
binaries/data/mods/public/gui/summary/summary.xml
diff --git a/binaries/data/mods/public/gui/summary/summary.xml b/binaries/data/mods/public/gui/summary/summary.xml index 2c47f16..015638f 100644
a b 103 103 <object name="playerNameHeading" type="text" style="ModernLeftTabLabelText"> 104 104 <translatableAttribute id="caption">Player name</translatableAttribute> 105 105 </object> 106 <repeat var="x" count=" 8">106 <repeat var="x" count="12"> 107 107 <object name="titleHeading[x]" type="text" style="ModernTabLabelText"> 108 108 </object> 109 109 </repeat> 110 <repeat var="x" count=" 8">110 <repeat var="x" count="12"> 111 111 <object name="Heading[x]" type="text" style="ModernTabLabelText"> 112 112 </object> 113 113 </repeat> … … 124 124 </object> 125 125 <object name="playerNamet[i][n]" type="text" size="40 2 208 100%" style="ModernLeftLabelText"/> 126 126 <object name="civIcont[i][n]" type="image" size="208 5 240 37" /> 127 <repeat var="x" count=" 8">127 <repeat var="x" count="12"> 128 128 <object name="valueDataTeam[i][n][x]" type="text" style="ModernTabLabelText"> 129 129 </object> 130 130 </repeat> … … 132 132 </repeat> 133 133 </object> 134 134 <object name="teamHeadingt[i]" type="text" style="ModernLeftTabLabelText"/> 135 <repeat var="x" count=" 8">135 <repeat var="x" count="12"> 136 136 <object name="valueDataTeam[i][x]" type="text" style="ModernTabLabelText"> 137 137 </object> 138 138 </repeat> … … 147 147 </object> 148 148 <object name="playerName[n]" type="text" size="40 2 208 100%" style="ModernLeftLabelText"/> 149 149 <object name="civIcon[n]" type="image" size="208 5 240 37"/> 150 <repeat var="x" count=" 8">150 <repeat var="x" count="12"> 151 151 <object name="valueData[n][x]" type="text" style="ModernTabLabelText"> 152 152 </object> 153 153 </repeat> -
binaries/data/mods/public/l10n/messages.json
diff --git a/binaries/data/mods/public/l10n/messages.json b/binaries/data/mods/public/l10n/messages.json index 188e3cc..34bd751 100644
a b 289 289 } 290 290 } 291 291 }, 292 292 { 293 293 "extractor": "json", 294 294 "filemasks": [ 295 295 "gui/credits/texts/**.json" … … 562 562 "description" 563 563 ] 564 564 } 565 }, 566 { 567 "extractor": "json", 568 "filemasks": [ 569 "simulation/data/resources/**.json" 570 ], 571 "options": { 572 "keywords": [ 573 "name", 574 "subtypes" 575 ], 576 "context": "firstWord" 577 } 578 }, 579 { 580 "extractor": "json", 581 "filemasks": [ 582 "simulation/data/resources/**.json" 583 ], 584 "options": { 585 "keywords": [ 586 "name", 587 "subtypes" 588 ], 589 "context": "withinSentence" 590 } 565 591 } 566 592 ] 567 593 }, -
binaries/data/mods/public/simulation/ai/common-api/resources.js
diff --git a/binaries/data/mods/public/simulation/ai/common-api/resources.js b/binaries/data/mods/public/simulation/ai/common-api/resources.js index 8130676..b6fe84b 100644
a b m.Resources = function(amounts = {}, population = 0) 9 9 this.population = population > 0 ? population : 0; 10 10 }; 11 11 12 m.Resources.prototype.types = []; // This array will be filled in SharedScript.init 12 // This array will be filled in SharedScript.init 13 m.Resources.prototype.types = []; 13 14 14 15 m.Resources.prototype.reset = function() 15 16 { -
binaries/data/mods/public/simulation/ai/common-api/shared.js
diff --git a/binaries/data/mods/public/simulation/ai/common-api/shared.js b/binaries/data/mods/public/simulation/ai/common-api/shared.js index 68ab45d..0e7b6c5 100644
a b m.SharedScript.prototype.init = function(state, deserialization) 180 180 this.accessibility.init(state, this.terrainAnalyzer); 181 181 182 182 // Setup resources 183 this.resourceTypes = { "food": 0, "wood": 1, "stone": 2, "metal": 2 }; 184 this.resourceList = []; 185 for (let res in this.resourceTypes) 186 this.resourceList.push(res); 187 m.Resources.prototype.types = this.resourceList; 183 this.resourceInfo = state.resources; 184 m.Resources.prototype.types = state.resources.codes; 188 185 // Resource types: 0 = not used for resource maps 189 // 1 = ab ondant resource with small amount each186 // 1 = abundant resource with small amount each 190 187 // 2 = spare resource, but huge amount each 191 188 // The following maps are defined in TerrainAnalysis.js and are used for some building placement (cc, dropsites) 192 189 // They are updated by checking for create and destroy events for all resources … … m.SharedScript.prototype.init = function(state, deserialization) 197 194 this.ccResourceMaps = {}; // Contains maps showing the density of resources, optimized for CC placement. 198 195 this.createResourceMaps(); 199 196 200 /** Keep in sync with gui/common/l10n.js */201 this.resourceNames = {202 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).203 "food": markForTranslationWithContext("withinSentence", "Food"),204 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).205 "wood": markForTranslationWithContext("withinSentence", "Wood"),206 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).207 "metal": markForTranslationWithContext("withinSentence", "Metal"),208 // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language).209 "stone": markForTranslationWithContext("withinSentence", "Stone"),210 };211 212 197 this.gameState = {}; 213 198 for (let i in this._players) 214 199 { -
binaries/data/mods/public/simulation/ai/common-api/terrain-analysis.js
diff --git a/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis.js b/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis.js index 04633dc..0639911 100644
a b m.Accessibility.prototype.floodFill = function(startIndex, value, onWater) 383 383 /** creates a map of resource density */ 384 384 m.SharedScript.prototype.createResourceMaps = function() 385 385 { 386 for (let resource of this.resource List)386 for (let resource of this.resourceInfo.codes) 387 387 { 388 if (this.resource Types[resource] !== 1 && this.resourceTypes[resource] !== 2)388 if (this.resourceInfo.aiInfluenceGroups[resource] === 0) 389 389 continue; 390 390 // if there is no resourceMap create one with an influence for everything with that resource 391 391 if (this.resourceMaps[resource]) … … m.SharedScript.prototype.createResourceMaps = function() 405 405 let cellSize = this.resourceMaps[resource].cellSize; 406 406 let x = Math.floor(ent.position()[0] / cellSize); 407 407 let z = Math.floor(ent.position()[1] / cellSize); 408 let type = this.resourceTypes[resource];409 let strength = Math.floor(ent.resourceSupplyMax() /this.normalizationFactor[type]);410 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[ type]/cellSize, strength/2, "constant");411 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[ type]/cellSize, strength/2);412 this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[ type]/cellSize, strength, "constant");408 let grp = this.resourceInfo.aiInfluenceGroups[resource]; 409 let strength = Math.floor(ent.resourceSupplyMax() / this.normalizationFactor[grp]); 410 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2, "constant"); 411 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2); 412 this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[grp] / cellSize, strength, "constant"); 413 413 } 414 414 }; 415 415 … … m.SharedScript.prototype.createResourceMaps = function() 420 420 */ 421 421 m.SharedScript.prototype.updateResourceMaps = function(events) 422 422 { 423 for (let resource of this.resource List)423 for (let resource of this.resourceInfo.codes) 424 424 { 425 if (this.resource Types[resource] !== 1 && this.resourceTypes[resource] !== 2)425 if (this.resourceInfo.aiInfluenceGroups[resource] === 0) 426 426 continue; 427 427 // if there is no resourceMap create one with an influence for everything with that resource 428 428 if (this.resourceMaps[resource]) … … m.SharedScript.prototype.updateResourceMaps = function(events) 447 447 let cellSize = this.resourceMaps[resource].cellSize; 448 448 let x = Math.floor(ent.position()[0] / cellSize); 449 449 let z = Math.floor(ent.position()[1] / cellSize); 450 let type = this.resourceTypes[resource];451 let strength = -Math.floor(ent.resourceSupplyMax() /this.normalizationFactor[type]);452 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[ type]/cellSize, strength/2, "constant");453 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[ type]/cellSize, strength/2);454 this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[ type]/cellSize, strength, "constant");450 let grp = this.resourceInfo.aiInfluenceGroups[resource]; 451 let strength = -Math.floor(ent.resourceSupplyMax() / this.normalizationFactor[grp]); 452 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2, "constant"); 453 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2); 454 this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[grp] / cellSize, strength, "constant"); 455 455 } 456 456 for (let e of events.Create) 457 457 { … … m.SharedScript.prototype.updateResourceMaps = function(events) 466 466 let cellSize = this.resourceMaps[resource].cellSize; 467 467 let x = Math.floor(ent.position()[0] / cellSize); 468 468 let z = Math.floor(ent.position()[1] / cellSize); 469 let type = this.resourceTypes[resource];470 let strength = Math.floor(ent.resourceSupplyMax() /this.normalizationFactor[type]);471 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[ type]/cellSize, strength/2, "constant");472 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[ type]/cellSize, strength/2);473 this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[ type]/cellSize, strength, "constant");469 let grp = this.resourceInfo.aiInfluenceGroups[resource]; 470 let strength = Math.floor(ent.resourceSupplyMax() / this.normalizationFactor[grp]); 471 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2, "constant"); 472 this.resourceMaps[resource].addInfluence(x, z, this.influenceRadius[grp] / cellSize, strength/2); 473 this.ccResourceMaps[resource].addInfluence(x, z, this.ccInfluenceRadius[grp] / cellSize, strength, "constant"); 474 474 } 475 475 }; 476 476 -
binaries/data/mods/public/simulation/ai/petra/baseManager.js
diff --git a/binaries/data/mods/public/simulation/ai/petra/baseManager.js b/binaries/data/mods/public/simulation/ai/petra/baseManager.js index f1b338f..1c823c7 100644
a b m.BaseManager.prototype.init = function(gameState, state) 55 55 this.dropsites = {}; 56 56 this.dropsiteSupplies = {}; 57 57 this.gatherers = {}; 58 for (let res of gameState.sharedScript.resource List)58 for (let res of gameState.sharedScript.resourceInfo.codes) 59 59 { 60 60 this.dropsiteSupplies[res] = { "nearby": [], "medium": [], "faraway": [] }; 61 61 this.gatherers[res] = { "nextCheck": 0, "used": 0, "lost": 0 }; … … m.BaseManager.prototype.getResourceLevel = function (gameState, type, nearbyOnly 434 434 /** check our resource levels and react accordingly */ 435 435 m.BaseManager.prototype.checkResourceLevels = function (gameState, queues) 436 436 { 437 for (let type of gameState.sharedScript.resource List)437 for (let type of gameState.sharedScript.resourceInfo.codes) 438 438 { 439 439 if (type === "food") 440 440 { -
binaries/data/mods/public/simulation/ai/petra/chatHelper.js
diff --git a/binaries/data/mods/public/simulation/ai/petra/chatHelper.js b/binaries/data/mods/public/simulation/ai/petra/chatHelper.js index 60999e8..1ef89be 100644
a b m.chatLaunchAttack = function(gameState, player, type) 17 17 "message": message, 18 18 "translateMessage": true, 19 19 "translateParameters": ["_player_"], 20 "parameters": { "_player_": player}20 "parameters": { "_player_": player } 21 21 }); 22 22 }; 23 23 … … m.chatAnswerRequestAttack = function(gameState, player, answer, other) 45 45 "message": message, 46 46 "translateMessage": true, 47 47 "translateParameters": ["_player_"], 48 "parameters": { "_player_": player}48 "parameters": { "_player_": player } 49 49 }; 50 50 if (other !== undefined) 51 51 { … … m.chatSentTribute = function(gameState, player) 71 71 "message": message, 72 72 "translateMessage": true, 73 73 "translateParameters": ["_player_"], 74 "parameters": { "_player_": player}74 "parameters": { "_player_": player } 75 75 }); 76 76 }; 77 77 … … m.chatRequestTribute = function(gameState, resource) 90 90 "type": "aichat", 91 91 "message": message, 92 92 "translateMessage": true, 93 "translateParameters": { "resource": "withinSentence"},94 "parameters": { "resource": gameState.sharedScript.resourceNames[resource]}93 "translateParameters": { "resource": "withinSentence" }, 94 "parameters": { "resource": gameState.sharedScript.resourceInfo.names[resource] } 95 95 }); 96 96 }; 97 97 … … m.chatNewTradeRoute = function(gameState, player) 109 109 "message": message, 110 110 "translateMessage": true, 111 111 "translateParameters": ["_player_"], 112 "parameters": { "_player_": player}112 "parameters": { "_player_": player } 113 113 }); 114 114 }; 115 115 -
binaries/data/mods/public/simulation/ai/petra/config.js
diff --git a/binaries/data/mods/public/simulation/ai/petra/config.js b/binaries/data/mods/public/simulation/ai/petra/config.js index d5dc6b3..b0f5e7f 100644
a b m.Config = function(difficulty) 103 103 "defensive": 0.5 104 104 }; 105 105 106 this.resources = ["food", "wood", "stone", "metal"]; 106 // See m.QueueManager.prototype.wantedGatherRates() 107 this.queues = 108 { 109 "firstTurn": { 110 "food": 10, 111 "wood": 10, 112 "default": 0 113 }, 114 "short": { 115 "food": 200, 116 "wood": 200, 117 "default": 100 118 }, 119 "medium": { 120 "default": 0 121 }, 122 "long": { 123 "default": 0 124 } 125 }; 107 126 }; 108 127 109 128 m.Config.prototype.setConfig = function(gameState) -
binaries/data/mods/public/simulation/ai/petra/headquarters.js
diff --git a/binaries/data/mods/public/simulation/ai/petra/headquarters.js b/binaries/data/mods/public/simulation/ai/petra/headquarters.js index 3e67da9..871035f 100644
a b m.HQ.prototype.init = function(gameState, queues) 69 69 this.navalMap = false; 70 70 this.navalRegions = {}; 71 71 72 for (let res of gameState.sharedScript.resource List)72 for (let res of gameState.sharedScript.resourceInfo.codes) 73 73 { 74 74 this.wantedRates[res] = 0; 75 75 this.currentRates[res] = 0; … … m.HQ.prototype.bulkPickWorkers = function(gameState, baseRef, number) 653 653 m.HQ.prototype.getTotalResourceLevel = function(gameState) 654 654 { 655 655 let total = {}; 656 for (let res of gameState.sharedScript.resource List)656 for (let res of gameState.sharedScript.resourceInfo.codes) 657 657 total[res] = 0; 658 658 for (let base of this.baseManagers) 659 659 for (let res in total) -
binaries/data/mods/public/simulation/ai/petra/queueManager.js
diff --git a/binaries/data/mods/public/simulation/ai/petra/queueManager.js b/binaries/data/mods/public/simulation/ai/petra/queueManager.js index 4691d11..671131d 100644
a b m.QueueManager.prototype.wantedGatherRates = function(gameState) 84 84 if (gameState.ai.playedTurn === 0) 85 85 { 86 86 let ret = {}; 87 for (let res of gameState.sharedScript.resource List)88 ret[res] = (res === "food" || res === "wood" ) ? 10 : 0;87 for (let res of gameState.sharedScript.resourceInfo.codes) 88 ret[res] = this.Config.queues.firstTurn[res] || this.Config.queues.firstTurn.default; 89 89 return ret; 90 90 } 91 91 … … m.QueueManager.prototype.wantedGatherRates = function(gameState) 97 97 let totalShort = {}; 98 98 let totalMedium = {}; 99 99 let totalLong = {}; 100 for (let res of gameState.sharedScript.resource List)100 for (let res of gameState.sharedScript.resourceInfo.codes) 101 101 { 102 totalShort[res] = (res === "food" || res === "wood" ) ? 200 : 100;103 totalMedium[res] = 0;104 totalLong[res] = 0;102 totalShort[res] = this.Config.queues.short[res] || this.Config.queues.short.default; 103 totalMedium[res] = this.Config.queues.medium[res] || this.Config.queues.medium.default; 104 totalLong[res] = this.Config.queues.long[res] || this.Config.queues.long.default; 105 105 } 106 106 let total; 107 107 //queueArrays because it's faster. … … m.QueueManager.prototype.wantedGatherRates = function(gameState) 133 133 // global rates 134 134 let rates = {}; 135 135 let diff; 136 for (let res of gameState.sharedScript.resource List)136 for (let res of gameState.sharedScript.resourceInfo.codes) 137 137 { 138 138 if (current[res] > 0) 139 139 { -
binaries/data/mods/public/simulation/ai/petra/researchManager.js
diff --git a/binaries/data/mods/public/simulation/ai/petra/researchManager.js b/binaries/data/mods/public/simulation/ai/petra/researchManager.js index f169b39..8e409a1 100644
a b m.ResearchManager.prototype.researchWantedTechs = function(gameState, techs) 100 100 let cost = template.cost; 101 101 let costMax = 0; 102 102 for (let res in cost) 103 costMax = Math.max(costMax, Math.max(cost[res]-available[res], 0)); 103 if (gameState.sharedScript.resourceInfo.codes.indexOf(res)) 104 costMax = Math.max(costMax, Math.max(cost[res]-available[res], 0)); 104 105 if (10*numWorkers < costMax) 105 106 continue; 106 107 } -
binaries/data/mods/public/simulation/components/Barter.js
diff --git a/binaries/data/mods/public/simulation/components/Barter.js b/binaries/data/mods/public/simulation/components/Barter.js index 24c39a4..106d1e3 100644
a b 1 // T rue price of 100 units of resource (for case if some resource is more worth).1 // The "true price" is a base price of 100 units of resource (for the case of some resources being of more worth than others). 2 2 // With current bartering system only relative values makes sense 3 3 // so if for example stone is two times more expensive than wood, 4 4 // there will 2:1 exchange rate. 5 const TRUE_PRICES = { "food": 100, "wood": 100, "stone": 100, "metal": 100 }; 6 5 // 7 6 // Constant part of price difference between true price and buy/sell price. 8 7 // In percents. 9 8 // Buy price equal to true price plus constant difference. … … const DIFFERENCE_RESTORE = 0.5; 21 20 // Interval of timer which slowly restore prices after deals 22 21 const RESTORE_TIMER_INTERVAL = 5000; 23 22 24 // Array of resource names25 const RESOURCES = ["food", "wood", "stone", "metal"];26 27 23 function Barter() {} 28 24 29 25 Barter.prototype.Schema = … … Barter.prototype.Schema = 32 28 Barter.prototype.Init = function() 33 29 { 34 30 this.priceDifferences = {}; 35 for ( var resource of RESOURCES)31 for (let resource of Resources.GetCodes()) 36 32 this.priceDifferences[resource] = 0; 37 33 this.restoreTimer = undefined; 38 34 }; … … Barter.prototype.Init = function() 40 36 Barter.prototype.GetPrices = function() 41 37 { 42 38 var prices = { "buy": {}, "sell": {} }; 43 for ( var resource of RESOURCES)39 for (let resource of Resources.GetCodes()) 44 40 { 45 prices["buy"][resource] = TRUE_PRICES[resource] * (100 + CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100; 46 prices["sell"][resource] = TRUE_PRICES[resource] * (100 - CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100; 41 let truePrice = Resources.GetResource(resource).truePrice; 42 prices.buy[resource] = truePrice * (100 + CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100; 43 prices.sell[resource] = truePrice * (100 - CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100; 47 44 } 48 45 return prices; 49 46 }; … … Barter.prototype.ExchangeResources = function(playerEntity, resourceToSell, reso 71 68 warn("ExchangeResources: incorrect amount: " + uneval(amount)); 72 69 return; 73 70 } 74 if (RESOURCES.indexOf(resourceToSell) == -1) 71 let availResources = Resources.GetCodes(); 72 if (availResources.indexOf(resourceToSell) == -1) 75 73 { 76 74 warn("ExchangeResources: incorrect resource to sell: " + uneval(resourceToSell)); 77 75 return; 78 76 } 79 if ( RESOURCES.indexOf(resourceToBuy) == -1)77 if (availResources.indexOf(resourceToBuy) == -1) 80 78 { 81 79 warn("ExchangeResources: incorrect resource to buy: " + uneval(resourceToBuy)); 82 80 return; … … Barter.prototype.ExchangeResources = function(playerEntity, resourceToSell, reso 123 121 Barter.prototype.ProgressTimeout = function(data) 124 122 { 125 123 var needRestore = false; 126 for ( var resource of RESOURCES)124 for (let resource of Resources.GetCodes()) 127 125 { 128 126 // Calculate value to restore, it should be limited to [-DIFFERENCE_RESTORE; DIFFERENCE_RESTORE] interval 129 127 var differenceRestore = Math.min(DIFFERENCE_RESTORE, Math.max(-DIFFERENCE_RESTORE, this.priceDifferences[resource])); -
binaries/data/mods/public/simulation/components/Cost.js
diff --git a/binaries/data/mods/public/simulation/components/Cost.js b/binaries/data/mods/public/simulation/components/Cost.js index b3196a6..9fd3ad3 100644
a b 1 1 function Cost() {} 2 2 3 Cost.prototype.ResourcesSchema = Resources.BuildSchema("nonNegativeDecimal"); 4 3 5 Cost.prototype.Schema = 4 6 "<a:help>Specifies the construction/training costs of this entity.</a:help>" + 5 7 "<a:example>" + … … Cost.prototype.Schema = 19 21 "<element name='PopulationBonus' a:help='Population cap increase while this entity exists'>" + 20 22 "<data type='nonNegativeInteger'/>" + 21 23 "</element>" + 22 "<element name='BuildTime' a:help='Time taken to construct/train this unit(in seconds)'>" +24 "<element name='BuildTime' a:help='Time taken to construct/train this entity (in seconds)'>" + 23 25 "<ref name='nonNegativeDecimal'/>" + 24 26 "</element>" + 25 "<element name='Resources' a:help='Resource costs to construct/train this unit'>" + 26 "<interleave>" + 27 "<element name='food'><ref name='nonNegativeDecimal'/></element>" + 28 "<element name='wood'><ref name='nonNegativeDecimal'/></element>" + 29 "<element name='stone'><ref name='nonNegativeDecimal'/></element>" + 30 "<element name='metal'><ref name='nonNegativeDecimal'/></element>" + 31 "</interleave>" + 27 "<element name='Resources' a:help='Resource costs to construct/train this entity'>" + 28 Cost.prototype.ResourcesSchema + 32 29 "</element>"; 33 30 34 31 Cost.prototype.Init = function() … … Cost.prototype.GetResourceCosts = function(owner) 70 67 let entityTemplate = cmpTemplateManager.GetTemplate(entityTemplateName); 71 68 72 69 let costs = {}; 73 for (let r in this.template.Resources) 74 costs[r] = ApplyValueModificationsToTemplate("Cost/Resources/"+r, +this.template.Resources[r], owner, entityTemplate); 70 let resCodes = Resources.GetCodes(); 71 72 for (let res in this.template.Resources) 73 { 74 if (resCodes.indexOf(res) < 0) 75 continue; 76 costs[res] = ApplyValueModificationsToTemplate("Cost/Resources/"+res, +this.template.Resources[res], owner, entityTemplate); 77 } 78 75 79 return costs; 76 80 }; 77 81 -
binaries/data/mods/public/simulation/components/GuiInterface.js
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index aaa7855..1b89b40 100644
a b GuiInterface.prototype.GetSimulationState = function() 152 152 let cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter); 153 153 ret.barterPrices = cmpBarter.GetPrices(); 154 154 155 // Add Resource Codes, untranslated names and AI Analysis 156 ret.resources = { 157 "codes": Resources.GetCodes(), 158 "names": Resources.GetNames(), 159 "aiInfluenceGroups": {} 160 }; 161 for (let res of ret.resources.codes) 162 ret.resources.aiInfluenceGroups[res] = Resources.GetResource(res).aiAnalysisInfluenceGroup || 0; 163 155 164 // Add basic statistics to each player 156 165 for (let i = 0; i < numPlayers; ++i) 157 166 { … … GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd) 1269 1278 1270 1279 let result = { 1271 1280 "pieces": [], 1272 "cost": { " food": 0, "wood": 0, "stone": 0, "metal": 0, "population": 0, "populationBonus": 0, "time": 0 },1281 "cost": { "population": 0, "populationBonus": 0, "time": 0 }, 1273 1282 }; 1283 for (let res of Resources.GetCodes()) 1284 result.cost[res] = 0; 1274 1285 1275 1286 let previewEntities = []; 1276 1287 if (end.pos) … … GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd) 1545 1556 // copied over, so we need to fetch it from the template instead). 1546 1557 // TODO: we should really use a Cost object or at least some utility functions for this, this is mindless 1547 1558 // boilerplate that's probably duplicated in tons of places. 1548 result.cost.food += tplData.cost.food; 1549 result.cost.wood += tplData.cost.wood; 1550 result.cost.stone += tplData.cost.stone; 1551 result.cost.metal += tplData.cost.metal; 1552 result.cost.population += tplData.cost.population; 1553 result.cost.populationBonus += tplData.cost.populationBonus; 1554 result.cost.time += tplData.cost.time; 1559 let entries = Resources.GetCodes().concat("population", "populationBonus", "time"); 1560 for (let res of entries) 1561 result.cost[res] = tplData.cost[res]; 1555 1562 } 1556 1563 1557 1564 let canAfford = true; -
binaries/data/mods/public/simulation/components/Loot.js
diff --git a/binaries/data/mods/public/simulation/components/Loot.js b/binaries/data/mods/public/simulation/components/Loot.js index 3161340..b17fdb3 100644
a b 1 1 function Loot() {} 2 2 3 Loot.prototype.ResourcesSchema = Resources.BuildSchema("nonNegativeInteger", [ "xp" ]); 4 3 5 Loot.prototype.Schema = 4 "<optional>" + 5 "<element name='xp'><data type='nonNegativeInteger'/></element>" + 6 "</optional>" + 7 "<optional>" + 8 "<element name='food'><data type='nonNegativeInteger'/></element>" + 9 "</optional>" + 10 "<optional>" + 11 "<element name='wood'><data type='nonNegativeInteger'/></element>" + 12 "</optional>" + 13 "<optional>" + 14 "<element name='stone'><data type='nonNegativeInteger'/></element>" + 15 "</optional>" + 16 "<optional>" + 17 "<element name='metal'><data type='nonNegativeInteger'/></element>" + 18 "</optional>"; 6 "<a:help>Specifies the loot credited when this entity is killed.</a:help>" + 7 "<a:example>" + 8 "<xp>35</xp>" + 9 "<metal>10</metal>" + 10 "</a:example>" + 11 Loot.prototype.ResourcesSchema; 19 12 20 13 Loot.prototype.Serialize = null; // we have no dynamic state to save 21 14 … … Loot.prototype.GetXp = function() 26 19 27 20 Loot.prototype.GetResources = function() 28 21 { 29 return { 30 "food": +(this.template.food || 0), 31 "wood": +(this.template.wood || 0), 32 "metal": +(this.template.metal || 0), 33 "stone": +(this.template.stone || 0) 34 }; 22 let ret = {}; 23 for (let res of Resources.GetCodes()) 24 ret[res] = +this.template[res] || 0; 25 26 return ret; 35 27 }; 36 28 37 29 Engine.RegisterComponentType(IID_Loot, "Loot", Loot); -
binaries/data/mods/public/simulation/components/Player.js
diff --git a/binaries/data/mods/public/simulation/components/Player.js b/binaries/data/mods/public/simulation/components/Player.js index cb137dd..ce9371a 100644
a b Player.prototype.Init = function() 18 18 this.popBonuses = 0; // sum of population bonuses of player's entities 19 19 this.maxPop = 300; // maximum population 20 20 this.trainingBlocked = false; // indicates whether any training queue is currently blocked 21 this.resourceCount = { 22 "food": 300, 23 "wood": 300, 24 "metal": 300, 25 "stone": 300 26 }; 27 // goods for next trade-route and its proba in % (the sum of probas must be 100) 28 this.tradingGoods = [ 29 { "goods": "wood", "proba": 30 }, 30 { "goods": "stone", "proba": 35 }, 31 { "goods": "metal", "proba": 35 }, 32 ]; 21 this.resourceCount = {}; 22 this.tradingGoods = []; // goods for next trade-route and its proba in % (the sum of probas must be 100) 33 23 this.team = -1; // team number of the player, players on the same team will always have ally diplomatic status - also this is useful for team emblems, scoring, etc. 34 24 this.teamsLocked = false; 35 25 this.state = "active"; // game state - one of "active", "defeated", "won" … … Player.prototype.Init = function() 44 34 this.cheatsEnabled = false; 45 35 this.cheatTimeMultiplier = 1; 46 36 this.heroes = []; 47 this.resourceNames = { 48 "food": markForTranslation("Food"), 49 "wood": markForTranslation("Wood"), 50 "metal": markForTranslation("Metal"), 51 "stone": markForTranslation("Stone"), 52 }; 37 this.resourceNames = {}; 53 38 this.disabledTemplates = {}; 54 39 this.disabledTechnologies = {}; 55 40 this.startingTechnologies = []; 41 42 // Initial resources and trading goods probability in steps of 5 43 let resCodes = Resources.GetCodes(); 44 let quotient = Math.floor(20 / resCodes.length); 45 let remainder = 20 % resCodes.length; 46 for (let i in resCodes) 47 { 48 let res = resCodes[i]; 49 this.resourceCount[res] = 300; 50 this.resourceNames[res] = Resources.GetResource(res).name; 51 this.tradingGoods.push({ 52 "goods": res, 53 "proba": 5 * (quotient + (+i < remainder ? 1 : 0)) 54 }); 55 } 56 56 }; 57 57 58 58 Player.prototype.SetPlayerID = function(id) … … Player.prototype.UnBlockTraining = function() 197 197 198 198 Player.prototype.SetResourceCounts = function(resources) 199 199 { 200 if (resources.food !== undefined) 201 this.resourceCount.food = resources.food; 202 if (resources.wood !== undefined) 203 this.resourceCount.wood = resources.wood; 204 if (resources.stone !== undefined) 205 this.resourceCount.stone = resources.stone; 206 if (resources.metal !== undefined) 207 this.resourceCount.metal = resources.metal; 200 for (let res in resources) 201 if (this.resourceCount[res]) 202 this.resourceCount[res] = resources[res]; 208 203 }; 209 204 210 205 Player.prototype.GetResourceCounts = function() … … Player.prototype.SubtractResourcesOrNotify = function(amounts) 297 292 298 293 // Subtract the resources 299 294 for (var type in amounts) 300 this.resourceCount[type] -= amounts[type]; 295 if (this.resourceCount[type]) 296 this.resourceCount[type] -= amounts[type]; 301 297 302 298 return true; 303 299 }; … … Player.prototype.GetTradingGoods = function() 340 336 341 337 Player.prototype.SetTradingGoods = function(tradingGoods) 342 338 { 343 varsumProba = 0;344 for ( varresource in tradingGoods)339 let sumProba = 0; 340 for (let resource in tradingGoods) 345 341 sumProba += tradingGoods[resource]; 346 342 if (sumProba != 100) // consistency check 347 343 { 348 344 error("Player.js SetTradingGoods: " + uneval(tradingGoods)); 349 tradingGoods = { "food": 20, "wood":20, "stone":30, "metal":30 }; 345 let resCodes = Resources.GetCodes(); 346 for (let r = 0; r < resCodes.length; ++r) 347 tradingGoods[resCodes[r]] = r == 0 ? 100 : 0; 350 348 } 351 349 352 350 this.tradingGoods = []; 353 for ( varresource in tradingGoods)351 for (let resource in tradingGoods) 354 352 this.tradingGoods.push( {"goods": resource, "proba": tradingGoods[resource]} ); 355 353 }; 356 354 -
binaries/data/mods/public/simulation/components/ProductionQueue.js
diff --git a/binaries/data/mods/public/simulation/components/ProductionQueue.js b/binaries/data/mods/public/simulation/components/ProductionQueue.js index 6c72202..5023f7f 100644
a b const MAX_QUEUE_SIZE = 16; 3 3 4 4 function ProductionQueue() {} 5 5 6 ProductionQueue.prototype.ResourceSchema = Resources.BuildSchema("nonNegativeDecimal", [ "time" ]); 7 6 8 ProductionQueue.prototype.Schema = 7 9 "<a:help>Allows the building to train new units and research technologies</a:help>" + 8 10 "<a:example>" + … … ProductionQueue.prototype.Schema = 31 33 "</element>" + 32 34 "</optional>" + 33 35 "<element name='TechCostMultiplier' a:help='Multiplier to modify ressources cost and research time of technologies searched in this building.'>" + 34 "<interleave>" + 35 "<element name='food'><ref name='nonNegativeDecimal'/></element>" + 36 "<element name='wood'><ref name='nonNegativeDecimal'/></element>" + 37 "<element name='stone'><ref name='nonNegativeDecimal'/></element>" + 38 "<element name='metal'><ref name='nonNegativeDecimal'/></element>" + 39 "<element name='time'><ref name='nonNegativeDecimal'/></element>" + 40 "</interleave>" + 36 ProductionQueue.prototype.ResourceSchema + 41 37 "</element>"; 42 38 43 39 ProductionQueue.prototype.Init = function() … … ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat 260 256 // TODO: there should probably be a limit on the number of queued batches 261 257 // TODO: there should be a way for the GUI to determine whether it's going 262 258 // to be possible to add a batch (based on resource costs and length limits) 263 var cmpPlayer = QueryOwnerInterface(this.entity); 259 let cmpPlayer = QueryOwnerInterface(this.entity); 260 let resCodes = Resources.GetCodes(); 264 261 265 262 if (this.queue.length < MAX_QUEUE_SIZE) 266 263 { … … ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat 293 290 var buildTime = ApplyValueModificationsToTemplate("Cost/BuildTime", +template.Cost.BuildTime, cmpPlayer.GetPlayerID(), template); 294 291 var time = timeMult * buildTime; 295 292 296 for ( var rin template.Cost.Resources)293 for (let res in template.Cost.Resources) 297 294 { 298 costs[r] = ApplyValueModificationsToTemplate("Cost/Resources/"+r, +template.Cost.Resources[r], cmpPlayer.GetPlayerID(), template); 299 totalCosts[r] = Math.floor(count * costs[r]); 295 if (resCodes.indexOf(res) < 0) 296 continue; 297 costs[res] = ApplyValueModificationsToTemplate("Cost/Resources/"+res, +template.Cost.Resources[res], cmpPlayer.GetPlayerID(), template); 298 totalCosts[res] = Math.floor(count * costs[res]); 300 299 } 301 300 302 301 var population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, cmpPlayer.GetPlayerID(), template); … … ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat 341 340 let techCostMultiplier = this.GetTechCostMultiplier(); 342 341 let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier(); 343 342 344 varcost = {};343 let cost = {}; 345 344 for (let res in template.cost) 346 cost[res] = Math.floor(techCostMultiplier[res] * template.cost[res]); 345 { 346 if (resCodes.indexOf(res) < 0) 347 continue; 348 cost[res] = Math.floor((techCostMultiplier[res] || 1) * template.cost[res]); 349 } 347 350 348 351 // TrySubtractResources should report error to player (they ran out of resources) 349 352 if (!cmpPlayer.TrySubtractResources(cost)) … … ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat 361 364 "player": cmpPlayer.GetPlayerID(), 362 365 "count": 1, 363 366 "technologyTemplate": templateName, 364 "resources": deepcopy(template.cost), // need to copy to avoid serialization problems367 "resources": cost, 365 368 "productionStarted": false, 366 369 "timeTotal": time*1000, 367 370 "timeRemaining": time*1000, … … ProductionQueue.prototype.RemoveBatch = function(id) 433 436 // Refund the resource cost for this batch 434 437 var totalCosts = {}; 435 438 var cmpStatisticsTracker = QueryPlayerIDInterface(item.player, IID_StatisticsTracker); 436 for each (var r in ["food", "wood", "stone", "metal"])439 for (let r of Resources.GetCodes()) 437 440 { 441 if (!item.resources[r]) 442 continue; 438 443 totalCosts[r] = Math.floor(item.count * item.resources[r]); 439 444 if (cmpStatisticsTracker) 440 445 cmpStatisticsTracker.IncreaseResourceUsedCounter(r, -totalCosts[r]); -
binaries/data/mods/public/simulation/components/ResourceDropsite.js
diff --git a/binaries/data/mods/public/simulation/components/ResourceDropsite.js b/binaries/data/mods/public/simulation/components/ResourceDropsite.js index 819807c..a14ddaf 100644
a b 1 1 function ResourceDropsite() {} 2 2 3 ResourceDropsite.prototype.ResourceChoiceSchema = Resources.BuildChoicesSchema(); 4 3 5 ResourceDropsite.prototype.Schema = 4 6 "<element name='Types'>" + 5 7 "<list>" + 6 8 "<zeroOrMore>" + 7 "<choice>" + 8 "<value>food</value>" + 9 "<value>wood</value>" + 10 "<value>stone</value>" + 11 "<value>metal</value>" + 12 "</choice>" + 9 ResourceDropsite.prototype.ResourceChoiceSchema + 13 10 "</zeroOrMore>" + 14 11 "</list>" + 15 12 "</element>" + … … ResourceDropsite.prototype.Init = function() 24 21 }; 25 22 26 23 /** 27 * Returns the list of resource types accepted by this dropsite. 24 * Returns the list of resource types accepted by this dropsite, 25 * as defined by it being referred to in the template and the resource being enabled. 28 26 */ 29 27 ResourceDropsite.prototype.GetTypes = function() 30 28 { 31 29 let types = ApplyValueModificationsToEntity("ResourceDropsite/Types", this.template.Types, this.entity); 32 return types ? types.split(/\s+/) : []; 30 let resources = Resources.GetCodes(); 31 return types.split(/\s+/).filter(type => resources.indexOf(type.toLowerCase()) > -1); 33 32 }; 34 33 35 34 /** -
binaries/data/mods/public/simulation/components/ResourceGatherer.js
diff --git a/binaries/data/mods/public/simulation/components/ResourceGatherer.js b/binaries/data/mods/public/simulation/components/ResourceGatherer.js index acd5fbd..be597f9 100644
a b 1 1 function ResourceGatherer() {} 2 2 3 ResourceGatherer.prototype.ResourcesSchema = Resources.BuildSchema("positiveDecimal", [ "treasure" ], true); 4 ResourceGatherer.prototype.CapacitiesSchema = Resources.BuildSchema("positiveDecimal"); 5 3 6 ResourceGatherer.prototype.Schema = 4 7 "<a:help>Lets the unit gather resources from entities that have the ResourceSupply component.</a:help>" + 5 8 "<a:example>" + … … ResourceGatherer.prototype.Schema = 25 28 "<ref name='positiveDecimal'/>" + 26 29 "</element>" + 27 30 "<element name='Rates' a:help='Per-resource-type gather rate multipliers. If a resource type is not specified then it cannot be gathered by this unit'>" + 28 "<interleave>" + 29 "<optional><element name='food' a:help='Food gather rate (may be overridden by \"food.*\" subtypes)'><ref name='positiveDecimal'/></element></optional>" + 30 "<optional><element name='wood' a:help='Wood gather rate'><ref name='positiveDecimal'/></element></optional>" + 31 "<optional><element name='stone' a:help='Stone gather rate'><ref name='positiveDecimal'/></element></optional>" + 32 "<optional><element name='metal' a:help='Metal gather rate'><ref name='positiveDecimal'/></element></optional>" + 33 "<optional><element name='treasure' a:help='Treasure gather rate (only presense on value makes sense, size is only used to determine the delay before gathering, so it should be set to 1)'><ref name='positiveDecimal'/></element></optional>" + 34 "<optional><element name='food.fish' a:help='Fish gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" + 35 "<optional><element name='food.fruit' a:help='Fruit gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" + 36 "<optional><element name='food.grain' a:help='Grain gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" + 37 "<optional><element name='food.meat' a:help='Meat gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" + 38 "<optional><element name='food.milk' a:help='Milk gather rate (overrides \"food\")'><ref name='positiveDecimal'/></element></optional>" + 39 "<optional><element name='wood.tree' a:help='Tree gather rate (overrides \"wood\")'><ref name='positiveDecimal'/></element></optional>" + 40 "<optional><element name='wood.ruins' a:help='Tree gather rate (overrides \"wood\")'><ref name='positiveDecimal'/></element></optional>" + 41 "<optional><element name='stone.rock' a:help='Rock gather rate (overrides \"stone\")'><ref name='positiveDecimal'/></element></optional>" + 42 "<optional><element name='stone.ruins' a:help='Rock gather rate (overrides \"stone\")'><ref name='positiveDecimal'/></element></optional>" + 43 "<optional><element name='metal.ore' a:help='Ore gather rate (overrides \"metal\")'><ref name='positiveDecimal'/></element></optional>" + 44 "<optional><element name='treasure.food' a:help='Food treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" + 45 "<optional><element name='treasure.wood' a:help='Wood treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" + 46 "<optional><element name='treasure.stone' a:help='Stone treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" + 47 "<optional><element name='treasure.metal' a:help='Metal treasure gather rate (overrides \"treasure\")'><ref name='positiveDecimal'/></element></optional>" + 48 "</interleave>" + 31 ResourceGatherer.prototype.ResourcesSchema + 49 32 "</element>" + 50 33 "<element name='Capacities' a:help='Per-resource-type maximum carrying capacity'>" + 51 "<interleave>" + 52 "<element name='food' a:help='Food capacity'><ref name='positiveDecimal'/></element>" + 53 "<element name='wood' a:help='Wood capacity'><ref name='positiveDecimal'/></element>" + 54 "<element name='stone' a:help='Stone capacity'><ref name='positiveDecimal'/></element>" + 55 "<element name='metal' a:help='Metal capacity'><ref name='positiveDecimal'/></element>" + 56 "</interleave>" + 34 ResourceGatherer.prototype.CapacitiesSchema + 57 35 "</element>"; 58 36 59 37 ResourceGatherer.prototype.Init = function() … … ResourceGatherer.prototype.RecalculateGatherRatesAndCapacities = function() 137 115 this.rates = {}; 138 116 for (let r in this.template.Rates) 139 117 { 118 let type = r.split("."); 119 let res = Resources.GetResource(type[0]); 120 121 if (!res && type[0] !== "treasure" || type.length > 1 && res.subtypes.indexOf(type[1]) == -1) 122 continue; 123 140 124 let rate = ApplyValueModificationsToEntity("ResourceGatherer/Rates/" + r, +this.template.Rates[r], this.entity); 141 125 this.rates[r] = rate * this.baseSpeed; 142 126 } … … ResourceGatherer.prototype.GetRange = function() 174 158 175 159 /** 176 160 * Try to gather treasure 177 * @return 'true' if treasure is successfully gathered and 'false' in the other case161 * @return 'true' if treasure is successfully gathered, otherwise 'false' 178 162 */ 179 163 ResourceGatherer.prototype.TryInstantGather = function(target) 180 164 { -
binaries/data/mods/public/simulation/components/ResourceSupply.js
diff --git a/binaries/data/mods/public/simulation/components/ResourceSupply.js b/binaries/data/mods/public/simulation/components/ResourceSupply.js index 04e95da..b39a39d 100644
a b 1 1 function ResourceSupply() {} 2 2 3 ResourceSupply.prototype.ResourceChoiceSchema = Resources.BuildChoicesSchema(true, true); 4 3 5 ResourceSupply.prototype.Schema = 4 6 "<a:help>Provides a supply of one particular type of resource.</a:help>" + 5 7 "<a:example>" + … … ResourceSupply.prototype.Schema = 12 14 "<element name='Amount' a:help='Amount of resources available from this entity'>" + 13 15 "<choice><data type='nonNegativeInteger'/><value>Infinity</value></choice>" + 14 16 "</element>" + 15 "<element name='Type' a:help='Type of resources'>" + 16 "<choice>" + 17 "<value>wood.tree</value>" + 18 "<value>wood.ruins</value>" + 19 "<value>stone.rock</value>" + 20 "<value>stone.ruins</value>" + 21 "<value>metal.ore</value>" + 22 "<value>food.fish</value>" + 23 "<value>food.fruit</value>" + 24 "<value>food.grain</value>" + 25 "<value>food.meat</value>" + 26 "<value>food.milk</value>" + 27 "<value>treasure.wood</value>" + 28 "<value>treasure.stone</value>" + 29 "<value>treasure.metal</value>" + 30 "<value>treasure.food</value>" + 31 "</choice>" + 17 "<element name='Type' a:help='Type and Subtype of resource available from this entity'>" + 18 ResourceSupply.prototype.ResourceChoiceSchema + 32 19 "</element>" + 33 20 "<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" + 34 21 "<data type='nonNegativeInteger'/>" + … … ResourceSupply.prototype.Init = function() 45 32 this.amount = this.GetMaxAmount(); 46 33 47 34 this.gatherers = []; // list of IDs for each players 48 varcmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); // system component so that's safe.49 varnumPlayers = cmpPlayerManager.GetNumPlayers();50 for ( vari = 0; i <= numPlayers; ++i) // use "<=" because we want Gaia too.35 let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); // system component so that's safe. 36 let numPlayers = cmpPlayerManager.GetNumPlayers(); 37 for (let i = 0; i <= numPlayers; ++i) // use "<=" because we want Gaia too. 51 38 this.gatherers.push([]); 52 39 53 40 this.infinite = !isFinite(+this.template.Amount); 54 41 55 [this.type,this.subType] = this.template.Type.split('.'); 56 this.cachedType = { "generic" : this.type, "specific" : this.subType }; 42 [this.type, this.subtype] = this.template.Type.split('.'); 43 let resData = Resources.GetResource(this.type); 44 if (this.type === "treasure") 45 resData = { "subtypes": Resources.GetCodes() }; 46 47 // Remove entity from gameworld if the resource supplied by this entity is disabled or not valid. 48 if (!resData || resData.subtypes.indexOf(this.subtype) === -1) 49 Engine.DestroyEntity(this.entity); 57 50 51 this.cachedType = { "generic": this.type, "specific": this.subtype }; 58 52 }; 59 53 60 54 ResourceSupply.prototype.IsInfinite = function() -
binaries/data/mods/public/simulation/components/ResourceTrickle.js
diff --git a/binaries/data/mods/public/simulation/components/ResourceTrickle.js b/binaries/data/mods/public/simulation/components/ResourceTrickle.js index 5c554e7..7bed918 100644
a b 1 1 function ResourceTrickle() {} 2 2 3 ResourceTrickle.prototype.ResourcesSchema = Resources.BuildSchema("nonNegativeDecimal"); 4 3 5 ResourceTrickle.prototype.Schema = 4 6 "<a:help>Controls the resource trickle ability of the unit.</a:help>" + 5 7 "<element name='Rates' a:help='Trickle Rates'>" + 6 "<interleave>" + 7 "<optional>" + 8 "<element name='food' a:help='Food given to the player every interval'>" + 9 "<ref name='nonNegativeDecimal'/>" + 10 "</element>" + 11 "</optional>" + 12 "<optional>" + 13 "<element name='wood' a:help='Wood given to the player every interval'>" + 14 "<ref name='nonNegativeDecimal'/>" + 15 "</element>" + 16 "</optional>" + 17 "<optional>" + 18 "<element name='stone' a:help='Stone given to the player every interval'>" + 19 "<ref name='nonNegativeDecimal'/>" + 20 "</element>" + 21 "</optional>" + 22 "<optional>" + 23 "<element name='metal' a:help='Metal given to the player every interval'>" + 24 "<ref name='nonNegativeDecimal'/>" + 25 "</element>" + 26 "</optional>" + 27 "</interleave>" + 8 ResourceTrickle.prototype.ResourcesSchema + 28 9 "</element>" + 29 10 "<element name='Interval' a:help='Number of miliseconds must pass for the player to gain the next trickle.'>" + 30 11 "<ref name='nonNegativeDecimal'/>" + … … ResourceTrickle.prototype.GetTimer = function() 45 26 46 27 ResourceTrickle.prototype.GetRates = function() 47 28 { 48 var rates = {}; 49 for (var resource in this.template.Rates) 29 let rates = {}; 30 let resCodes = Resources.GetCodes(); 31 for (let resource in this.template.Rates) 32 { 33 if (resCodes.indexOf(resource) < 0) 34 continue; 50 35 rates[resource] = ApplyValueModificationsToEntity("ResourceTrickle/Rates/"+resource, +this.template.Rates[resource], this.entity); 36 } 51 37 52 38 return rates; 53 39 }; … … ResourceTrickle.prototype.GetRates = function() 55 41 // Do the actual work here 56 42 ResourceTrickle.prototype.Trickle = function(data, lateness) 57 43 { 58 var cmpPlayer = QueryOwnerInterface(this.entity); 59 if (!cmpPlayer) 60 return; 61 62 var rates = this.GetRates(); 63 for (var resource in rates) 64 cmpPlayer.AddResource(resource, rates[resource]); 44 let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 45 if (cmpPlayer) 46 cmpPlayer.AddResources(this.GetRates()); 65 47 }; 66 48 67 49 Engine.RegisterComponentType(IID_ResourceTrickle, "ResourceTrickle", ResourceTrickle); -
binaries/data/mods/public/simulation/components/StatisticsTracker.js
diff --git a/binaries/data/mods/public/simulation/components/StatisticsTracker.js b/binaries/data/mods/public/simulation/components/StatisticsTracker.js index 3bc1f79..482502d 100644
a b StatisticsTracker.prototype.Init = function() 105 105 this.buildingsCapturedValue = 0; 106 106 107 107 this.resourcesGathered = { 108 "food": 0,109 "wood": 0,110 "metal": 0,111 "stone": 0,112 108 "vegetarianFood": 0 113 109 }; 114 this.resourcesUsed = { 115 "food": 0, 116 "wood": 0, 117 "metal": 0, 118 "stone": 0 119 }; 120 this.resourcesSold = { 121 "food": 0, 122 "wood": 0, 123 "metal": 0, 124 "stone": 0 125 }; 126 this.resourcesBought = { 127 "food": 0, 128 "wood": 0, 129 "metal": 0, 130 "stone": 0 131 }; 110 this.resourcesUsed = {}; 111 this.resourcesSold = {}; 112 this.resourcesBought = {}; 113 for (let res of Resources.GetCodes()) 114 { 115 this.resourcesGathered[res] = 0; 116 this.resourcesUsed[res] = 0; 117 this.resourcesSold[res] = 0; 118 this.resourcesBought[res] = 0; 119 } 132 120 133 121 this.tributesSent = 0; 134 122 this.tributesReceived = 0; … … StatisticsTracker.prototype.IncreaseResourceGatheredCounter = function(type, amo 347 335 */ 348 336 StatisticsTracker.prototype.IncreaseResourceUsedCounter = function(type, amount) 349 337 { 350 this.resourcesUsed[type] += amount; 338 if (typeof this.resourcesUsed[type] === "number") 339 this.resourcesUsed[type] += amount; 351 340 }; 352 341 353 342 StatisticsTracker.prototype.IncreaseTreasuresCollectedCounter = function() -
binaries/data/mods/public/simulation/components/Trader.js
diff --git a/binaries/data/mods/public/simulation/components/Trader.js b/binaries/data/mods/public/simulation/components/Trader.js index 735778d..771a814 100644
a b 4 4 // Additional gain for ships for each garrisoned trader, in percents 5 5 const GARRISONED_TRADER_ADDITION = 20; 6 6 7 // Array of resource names8 const RESOURCES = ["food", "wood", "stone", "metal"];9 10 7 function Trader() {} 11 8 12 9 Trader.prototype.Schema = -
binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
diff --git a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js index 6ae026e..f1c9e98 100644
a b Engine.LoadComponentScript("interfaces/Upgrade.js"); 33 33 Engine.LoadComponentScript("interfaces/BuildingAI.js"); 34 34 Engine.LoadComponentScript("GuiInterface.js"); 35 35 36 Resources = { 37 "GetCodes": () => ["food", "metal", "stone", "wood"], 38 "GetNames": () => ({ "food": "Food", "metal": "Metal", "stone": "Stone", "wood": "Wood" }), 39 "GetResource": () => ({}), 40 }; 41 36 42 var cmp = ConstructComponent(SYSTEM_ENTITY, "GuiInterface"); 37 43 38 44 … … TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), { 330 336 circularMap: false, 331 337 timeElapsed: 0, 332 338 gameType: "conquest", 333 barterPrices: {buy: {food: 150}, sell: {food: 25}} 339 barterPrices: { buy: { "food": 150 }, sell: { "food": 25 } }, 340 resources: { 341 codes: ["food", "metal", "stone", "wood"], 342 names: { 343 "food": "Food", 344 "metal": "Metal", 345 "stone": "Stone", 346 "wood": "Wood", 347 }, 348 aiInfluenceGroups: { 349 "food": 0, 350 "metal": 0, 351 "stone": 0, 352 "wood": 0, 353 } 354 }, 334 355 }); 335 356 336 357 TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), { … … TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), { 449 470 circularMap: false, 450 471 timeElapsed: 0, 451 472 gameType: "conquest", 452 barterPrices: {buy: {food: 150}, sell: {food: 25}} 473 barterPrices: { buy: { "food": 150 }, sell: { "food": 25 } }, 474 resources: { 475 codes: ["food", "metal", "stone", "wood"], 476 names: { 477 "food": "Food", 478 "metal": "Metal", 479 "stone": "Stone", 480 "wood": "Wood", 481 }, 482 aiInfluenceGroups: { 483 "food": 0, 484 "metal": 0, 485 "stone": 0, 486 "wood": 0, 487 } 488 }, 453 489 }); 454 490 455 491 -
binaries/data/mods/public/simulation/components/tests/test_Player.js
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Player.js b/binaries/data/mods/public/simulation/components/tests/test_Player.js index 4191a68..3649351 100644
a b Engine.LoadComponentScript("Timer.js") 9 9 ConstructComponent(SYSTEM_ENTITY, "EndGameManager"); 10 10 ConstructComponent(SYSTEM_ENTITY, "Timer"); 11 11 12 Resources = { 13 "GetCodes": () => ["food", "metal", "stone", "wood"], 14 "GetResource": () => ({}), 15 }; 16 12 17 var cmpPlayer = ConstructComponent(10, "Player"); 13 18 14 19 TS_ASSERT_EQUALS(cmpPlayer.GetPopulationCount(), 0); -
new file inaries/data/mods/public/simulation/data/resources/food.json
diff --git a/binaries/data/mods/public/simulation/data/resources/food.json b/binaries/data/mods/public/simulation/data/resources/food.json new file mode 100644 index 0000000..67c85e7
- + 1 { 2 "code": "food", 3 "name": "Food", 4 "subtypes": { 5 "fish": "Fish", 6 "fruit": "Fruit", 7 "grain": "Grain", 8 "meat": "Meat", 9 "milk": "Milk" 10 }, 11 "truePrice": 100, 12 "aiAnalysisInfluenceGroup": 0, 13 "enabled": true 14 } -
new file inaries/data/mods/public/simulation/data/resources/metal.json
diff --git a/binaries/data/mods/public/simulation/data/resources/metal.json b/binaries/data/mods/public/simulation/data/resources/metal.json new file mode 100644 index 0000000..2a8b590
- + 1 { 2 "code": "metal", 3 "name": "Metal", 4 "subtypes": { 5 "ore": "Ore" 6 }, 7 "truePrice": 100, 8 "aiAnalysisInfluenceGroup": 2, 9 "enabled": true 10 } -
new file inaries/data/mods/public/simulation/data/resources/stone.json
diff --git a/binaries/data/mods/public/simulation/data/resources/stone.json b/binaries/data/mods/public/simulation/data/resources/stone.json new file mode 100644 index 0000000..034783e
- + 1 { 2 "code": "stone", 3 "name": "Stone", 4 "subtypes": { 5 "rock": "Rock", 6 "ruins": "Ruins" 7 }, 8 "truePrice": 100, 9 "aiAnalysisInfluenceGroup": 2, 10 "enabled": true 11 } -
new file inaries/data/mods/public/simulation/data/resources/wood.json
diff --git a/binaries/data/mods/public/simulation/data/resources/wood.json b/binaries/data/mods/public/simulation/data/resources/wood.json new file mode 100644 index 0000000..9e5a904
- + 1 { 2 "code": "wood", 3 "name": "Wood", 4 "subtypes": { 5 "tree": "Tree", 6 "ruins": "Ruins" 7 }, 8 "truePrice": 100, 9 "aiAnalysisInfluenceGroup": 1, 10 "enabled": true 11 } -
new file inaries/data/mods/public/simulation/helpers/Resources.js
diff --git a/binaries/data/mods/public/simulation/helpers/Resources.js b/binaries/data/mods/public/simulation/helpers/Resources.js new file mode 100644 index 0000000..7c399b0
- + 1 /** 2 * Builds a RelaxRNG schema based on currently valid elements. 3 * 4 * To prevent validation errors, disabled resources are included in the schema. 5 * 6 * @param datatype - The datatype of the element 7 * @param additional - Array of additional data elements. Time, xp, treasure, etc. 8 * @param subtypes - If true, resource subtypes will be included as well. 9 * @return RelaxNG schema string 10 */ 11 Resources.prototype.BuildSchema = function(datatype, additional = [], subtypes = false) 12 { 13 if (!datatype) 14 return ""; 15 16 switch (datatype) 17 { 18 case "decimal": 19 case "nonNegativeDecimal": 20 case "positiveDecimal": 21 datatype = "<ref name='" + datatype + "'/>"; 22 break; 23 24 default: 25 datatype = "<data type='" + datatype + "'/>"; 26 } 27 28 let resCodes = this.resourceData.map(resource => resource.code); 29 let schema = ""; 30 for (let res of resCodes.concat(additional)) 31 schema += 32 "<optional>" + 33 "<element name='" + res + "'>" + 34 datatype + 35 "</element>" + 36 "</optional>"; 37 38 if (!subtypes) 39 return "<interleave>" + schema + "</interleave>"; 40 41 for (let res of this.resourceData) 42 for (let subtype of res.subtypes) 43 schema += 44 "<optional>" + 45 "<element name='" + res.code + "." + subtype + "'>" + 46 datatype + 47 "</element>" + 48 "</optional>"; 49 50 if (additional.indexOf("treasure") !== -1) 51 for (let res of resCodes) 52 schema += 53 "<optional>" + 54 "<element name='" + "treasure." + res + "'>" + 55 datatype + 56 "</element>" + 57 "</optional>"; 58 59 return "<interleave>" + schema + "</interleave>"; 60 } 61 62 /** 63 * Builds the value choices for a RelaxNG `<choice></choice>` object, based on currently valid resources. 64 * 65 * @oaram subtypes - If set to true, the choices returned will be resource subtypes, rather than main types 66 * @param treasure - If set to true, the pseudo resource 'treasure' (or its subtypes) will be included 67 * @return String of RelaxNG Schema `<choice/>` values. 68 */ 69 Resources.prototype.BuildChoicesSchema = function(subtypes = false, treasure = false) 70 { 71 let schema = ""; 72 73 if (!subtypes) 74 { 75 let resCodes = this.resourceData.map(resource => resource.code); 76 if (treasure) 77 resCodes.push("treasure"); 78 for (let res of resCodes) 79 schema += "<value>" + res + "</value>"; 80 } 81 else 82 for (let res of this.resourceData) 83 { 84 for (let subtype of res.subtypes) 85 schema += "<value>" + res.code + "." + subtype + "</value>"; 86 if (treasure) 87 schema += "<value>" + "treasure." + res.code + "</value>"; 88 } 89 90 return "<choice>" + schema + "</choice>"; 91 } 92 93 Resources = new Resources();