Ticket #3934: resource_agnostic-v3.patch
File resource_agnostic-v3.patch, 92.7 KB (added by , 8 years ago) |
---|
-
new file inaries/data/mods/public/gui/common/functions_repeat_positioning.js
diff --git a/binaries/data/mods/public/gui/common/functions_repeat_positioning.js b/binaries/data/mods/public/gui/common/functions_repeat_positioning.js new file mode 100644 index 0000000..113a049
- + 1 /* 2 DESCRIPTION : Functions related to positioning UI elements 3 NOTES : 4 */ 5 6 /** 7 * Horizontally fit objects repeated with the `<repeat>` tag within a parent object 8 * 9 * @param basename The base name of the object, such as "object[n]" or "object[a]_sub[b]" 10 * @param splitvar The var identifying the repeat count, without the square brackets 11 * @param margin The gap, in px, between the repeated objects 12 * @param limit The number of elements to fit 13 * @return The number of elements affected 14 */ 15 function horizFitRepeatedObjects(basename, splitvar="n", margin=0, limit=0) 16 { 17 basename = basename.split("["+splitvar+"]", 2); 18 19 let objObj; 20 if (limit == 0) 21 do 22 { 23 objObj = Engine.GetGUIObjectByName(basename.join("["+ ++limit +"]")); 24 } 25 while (objObj) 26 27 for (let c = 0; c < limit; ++c) 28 { 29 objObj = Engine.GetGUIObjectByName(basename.join("["+ c +"]")); 30 let objSize = objObj.size; 31 objSize.rleft = c * (100/limit); 32 objSize.rright = (c+1) * (100/limit); 33 objSize.right = -margin; 34 objObj.size = objSize; 35 } 36 37 return limit; 38 } 39 40 /** 41 * Hide all repeated elements after a certain index 42 * 43 * @param prefix The part of the element name preceeding the index 44 * @param idx The index from which to start 45 * @param prefix The part of the element name after the index 46 */ 47 function hideRemaining(prefix, idx, suffix) 48 { 49 while (true) 50 { 51 let obj = Engine.GetGUIObjectByName(prefix + idx + suffix); 52 if (!obj) 53 return; 54 obj.hidden = true; 55 ++idx; 56 } 57 } -
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/setup_resources.xml
diff --git a/binaries/data/mods/public/gui/common/setup_resources.xml b/binaries/data/mods/public/gui/common/setup_resources.xml index ffc9c4d..afbabdd 100644
a b 2 2 3 3 <setup> 4 4 <!-- Icons --> 5 <icon name="icon Food"5 <icon name="icon_food" 6 6 sprite="stretched:session/icons/resources/food_small.png" 7 7 size="16 16" 8 8 /> 9 <icon name="icon Metal"9 <icon name="icon_metal" 10 10 sprite="stretched:session/icons/resources/metal_small.png" 11 11 size="16 16" 12 12 /> 13 <icon name="icon Population"13 <icon name="icon_population" 14 14 sprite="stretched:session/icons/resources/population_small.png" 15 15 size="16 16" 16 16 /> 17 <icon name="icon Stone"17 <icon name="icon_stone" 18 18 sprite="stretched:session/icons/resources/stone_small.png" 19 19 size="16 16" 20 20 /> 21 <icon name="icon Wood"21 <icon name="icon_wood" 22 22 sprite="stretched:session/icons/resources/wood_small.png" 23 23 size="16 16" 24 24 /> 25 <icon name="icon Time"25 <icon name="icon_time" 26 26 sprite="stretched:session/icons/resources/time_small.png" 27 27 size="16 16" 28 28 /> -
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 6422947..172367e 100644
a b 1 const g_CostDisplayIcons = {2 "food": '[icon="iconFood"]',3 "wood": '[icon="iconWood"]',4 "stone": '[icon="iconStone"]',5 "metal": '[icon="iconMetal"]',6 "population": '[icon="iconPopulation"]',7 "time": '[icon="iconTime"]'8 };9 1 10 2 const g_TooltipTextFormats = { 11 3 "unit": ['[font="sans-10"][color="orange"]', '[/color][/font]'], … … function getBuildRateTooltip(rate) 260 252 */ 261 253 function getCostComponentDisplayIcon(costComponentName) 262 254 { 263 if (costComponentName in g_CostDisplayIcons) 264 return g_CostDisplayIcons[costComponentName]; 265 266 warn(sprintf("The specified cost component, ‘%(component)s’, is not currently supported.", { "component": costComponentName })); 267 return ""; 255 return "[icon=\"icon_"+costComponentName+"\"]"; 268 256 } 269 257 270 258 /** … … function getEntityCostComponentsTooltipString(template, trainNum, entity) 291 279 totalCosts.time = Math.ceil(template.cost.time * (entity ? Engine.GuiInterfaceCall("GetBatchTime", { "entity": entity, "batchSize": trainNum }) : 1)); 292 280 293 281 let costs = []; 294 295 for (let type in g_CostDisplayIcons) 296 if (totalCosts[type]) 297 costs.push(sprintf(translate("%(component)s %(cost)s"), { 298 "component": getCostComponentDisplayIcon(type), 299 "cost": totalCosts[type] 300 })); 282 283 for (let c in template.cost) 284 if (c === "populationBonus") 285 continue; 286 else if (totalCosts[c]) 287 if (typeof GetSimState === "undefined" || GetSimState().resources.codes.indexOf(c) > -1 || c === "time") 288 costs.push(sprintf(translate("%(component)s %(cost)s"), { 289 "component": getCostComponentDisplayIcon(c), 290 "cost": totalCosts[c] 291 })); 301 292 302 293 return costs; 303 294 } -
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..f2499d8 100644
a b 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 <!-- 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"/> 55 <!-- Tribute --> 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 44b004b..49446f2 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 openDiplomacy() 237 234 g_IsDiplomacyOpen = true; 238 235 239 236 let isCeasefireActive = GetSimState().ceasefireActive; 237 let resCodes = GetSimState().resources.codes; 240 238 241 239 // Get offset for one line 242 240 let onesize = Engine.GetGUIObjectByName("diplomacyPlayer[0]").size; … … function openDiplomacy() 255 253 diplomacyFormatAttackRequestButton(i, myself || playerInactive || isCeasefireActive || !hasAllies || !g_Players[i].isEnemy[g_ViewedPlayer]); 256 254 } 257 255 258 Engine.GetGUIObjectByName("diplomacyDialogPanel").hidden = false; 256 let dialog = Engine.GetGUIObjectByName("diplomacyDialogPanel"); 257 let size = dialog.size; 258 let wid = resCodes.length * 10; 259 size.left = -(260 + wid); 260 size.right = (260 + wid); 261 dialog.size = size; 262 dialog.hidden = false; 259 263 } 260 264 261 265 function diplomacySetupTexts(i, rowsize) … … function diplomacyFormatStanceButtons(i, hidden) 305 309 306 310 function diplomacyFormatTributeButtons(i, hidden) 307 311 { 308 for (let resource of RESOURCES) 312 let resources = GetSimState().resources; 313 let r = 0; 314 for (let resCode of resources.codes) 309 315 { 310 let button = Engine.GetGUIObjectByName("diplomacyPlayerTribute"+resource[0].toUpperCase()+resource.substring(1)+"["+(i-1)+"]"); 316 let button = Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]_tribute["+r+"]"); 317 Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]_tribute["+r+"]_image").sprite = "stretched:session/icons/resources/"+resCode+".png"; 311 318 button.hidden = hidden; 319 setPanelObjectPosition(button, r, 8, 0); 312 320 if (hidden) 313 321 continue; 322 ++r; 314 323 315 324 button.enabled = controlsPlayer(g_ViewedPlayer); 316 button.tooltip = formatTributeTooltip(i, resource , 100);317 button.onpress = (function(i, res ource, button) {325 button.tooltip = formatTributeTooltip(i, resources.names[resCode], 100); 326 button.onpress = (function(i, resCode, button) { 318 327 // Shift+click to send 500, shift+click+click to send 1000, etc. 319 328 // See INPUT_MASSTRIBUTING in input.js 320 329 let multiplier = 1; … … function diplomacyFormatTributeButtons(i, hidden) 327 336 } 328 337 329 338 let amounts = {}; 330 for (let type of RESOURCES)331 amounts[ type] = 0;332 amounts[res ource] = 100 * multiplier;339 for (let res of resources.codes) 340 amounts[res] = 0; 341 amounts[resCode] = 100 * multiplier, 333 342 334 button.tooltip = formatTributeTooltip(i, resource , amounts[resource]);343 button.tooltip = formatTributeTooltip(i, resources.names[resCode], amounts[resCode]); 335 344 336 345 // This is in a closure so that we have access to `player`, `amounts`, and `multiplier` without some 337 346 // evil global variable hackery. 338 347 g_FlushTributing = function() { 339 348 Engine.PostNetworkCommand({ "type": "tribute", "player": i, "amounts": amounts }); 340 349 multiplier = 1; 341 button.tooltip = formatTributeTooltip(i, resource , 100);350 button.tooltip = formatTributeTooltip(i, resources.names[resCode], 100); 342 351 }; 343 352 344 353 if (!isBatchTrainPressed) 345 354 g_FlushTributing(); 346 355 }; 347 })(i, res ource, button);356 })(i, resCode, button); 348 357 } 349 358 } 350 359 … … function openTrade() 398 407 } 399 408 }; 400 409 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) 410 let proba = Engine.GuiInterfaceCall("GetTradingGoods", g_ViewedPlayer); 411 let button = {}; 412 let resCodes = GetSimState().resources.codes; 413 let selec = resCodes[0]; 414 hideRemaining("tradeResource[", resCodes.length, "]"); 415 416 for (let i = 0; i < resCodes.length; ++i) 405 417 { 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 }; 418 let buttonResource = Engine.GetGUIObjectByName("tradeResource["+i+"]"); 419 setPanelObjectPosition(buttonResource, i, 8); 420 let resCode = resCodes[i]; 421 proba[resCode] = (proba[resCode] ? proba[resCode] : 0); 422 buttonResource = Engine.GetGUIObjectByName("tradeResourceButton["+i+"]"); 423 let icon = Engine.GetGUIObjectByName("tradeResourceIcon["+i+"]"); 424 icon.sprite = "stretched:session/icons/resources/" + resCode + ".png"; 425 let label = Engine.GetGUIObjectByName("tradeResourceText["+i+"]"); 426 let buttonUp = Engine.GetGUIObjectByName("tradeArrowUp["+i+"]"); 427 let buttonDn = Engine.GetGUIObjectByName("tradeArrowDn["+i+"]"); 428 let iconSel = Engine.GetGUIObjectByName("tradeResourceSelection["+i+"]"); 429 button[resCode] = { "up": buttonUp, "dn": buttonDn, "label": label, "sel": iconSel }; 425 430 426 431 buttonResource.enabled = controlsPlayer(g_ViewedPlayer); 427 432 buttonResource.onpress = (function(resource){ 428 433 return function() { 429 434 if (Engine.HotkeyIsPressed("session.fulltradeswap")) 430 435 { 431 for ( var ress of RESOURCES)436 for (let ress of resCodes) 432 437 proba[ress] = 0; 433 438 proba[resource] = 100; 434 439 Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); … … function openTrade() 436 441 selec = resource; 437 442 updateButtons(); 438 443 }; 439 })(res ource);444 })(resCode); 440 445 441 446 buttonUp.enabled = controlsPlayer(g_ViewedPlayer); 442 447 buttonUp.onpress = (function(resource){ … … function openTrade() 446 451 Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); 447 452 updateButtons(); 448 453 }; 449 })(res ource);454 })(resCode); 450 455 451 456 buttonDn.enabled = controlsPlayer(g_ViewedPlayer); 452 457 buttonDn.onpress = (function(resource){ … … function openTrade() 456 461 Engine.PostNetworkCommand({"type": "set-trading-goods", "tradingGoods": proba}); 457 462 updateButtons(); 458 463 }; 459 })(res ource);464 })(resCode); 460 465 } 461 466 updateButtons(); 462 467 … … function openTrade() 464 469 Engine.GetGUIObjectByName("landTraders").caption = getIdleLandTradersText(traderNumber); 465 470 Engine.GetGUIObjectByName("shipTraders").caption = getIdleShipTradersText(traderNumber); 466 471 467 Engine.GetGUIObjectByName("tradeDialogPanel").hidden = false; 472 let dialog = Engine.GetGUIObjectByName("tradeDialogPanel"); 473 let size = dialog.size; 474 let wid = resCodes.length * (58/2); 475 size.left = -(134 + wid); 476 size.right = (134 + wid); 477 dialog.size = size; 478 dialog.hidden = false; 468 479 } 469 480 470 481 function getIdleLandTradersText(traderNumber) -
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 a9b9af7..282fc3b 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 = GetSimState().resources.names[(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 e117d83..175ce0e 100644
a b g_SelectionPanels.Alert = { 87 87 g_SelectionPanels.Barter = { 88 88 "getMaxNumberOfItems": function() 89 89 { 90 return 4;90 return 8; 91 91 }, 92 92 "rowLength": 4, 93 93 "getItems": function(unitEntState, selection) 94 94 { 95 95 if (!unitEntState.barterMarket) 96 96 return []; 97 // ["food", "wood", "stone", "metal"] 98 return BARTER_RESOURCES; 97 return GetSimState().resources.codes; 99 98 }, 100 99 "setupButton": function(data) 101 100 { … … g_SelectionPanels.Barter = { 115 114 if (Engine.HotkeyIsPressed("session.massbarter")) 116 115 amountToSell *= BARTER_BUNCH_MULTIPLIER; 117 116 117 if (!g_BarterSell) 118 g_BarterSell = GetSimState().resources.codes[0]; 119 118 120 amount.Sell.caption = "-" + amountToSell; 119 121 let prices = data.unitEntState.barterMarket.prices; 120 122 amount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[data.item] * amountToSell); 121 123 122 let resource = getLocalizedResourceName( data.item, "withinSentence");124 let resource = getLocalizedResourceName(GetSimState().resources.names[data.item], "firstWord"); 123 125 button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource }); 124 126 button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource }); 125 127 … … g_SelectionPanels.Barter = { 163 165 button.Sell.hidden = false; 164 166 selectionIcon.hidden = !isSelected; 165 167 166 setPanelObjectPosition(button.Sell, data.i, data.rowLength); 167 setPanelObjectPosition(button.Buy, data.i + data.rowLength, data.rowLength); 168 let sellPos = data.i + (data.i >= data.rowLength ? data.rowLength : 0); 169 let buyPos = data.i + data.rowLength * (data.i >= data.rowLength ? 2 : 1); 170 setPanelObjectPosition(button.Sell, sellPos, data.rowLength); 171 setPanelObjectPosition(button.Buy, buyPos, data.rowLength); 168 172 return true; 169 173 } 170 174 }; -
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 681b65a..ae95910 100644
a b 2 2 // Barter constants 3 3 const BARTER_RESOURCE_AMOUNT_TO_SELL = 100; 4 4 const BARTER_BUNCH_MULTIPLIER = 5; 5 const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];6 5 const BARTER_ACTIONS = ["Sell", "Buy"]; 7 6 8 7 // Gate constants … … const GATE_ACTIONS = ["lock", "unlock"]; 10 9 11 10 // ============================================== 12 11 // BARTER HELPERS 13 // Resources to sell on barter panel 14 var g_BarterSell = "food"; 12 // Resource to sell by default on barter panel 13 // ! - cannot be set as we don't know the possible resources yet 14 var g_BarterSell = null; 15 15 16 // ============================================== 16 17 // FORMATION HELPERS 17 18 // Check if the selection can move into formation, and cache the result 18 19 function canMoveSelectionIntoFormation(formationTemplate) -
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..c28ef92 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 1a084f7..ba7eee6 100644
a b function updateTopPanel() 448 448 Engine.GetGUIObjectByName("civIconOverlay").tooltip = sprintf(translate("%(civ)s - Structure Tree"), { "civ": civName }); 449 449 } 450 450 451 let resources = GetSimState().resources; 452 let r = 0; 453 for (let resCode of resources.codes) 454 { 455 Engine.GetGUIObjectByName("resource["+r+"]").tooltip = getLocalizedResourceName(resources.names[resCode], "firstWord"); 456 Engine.GetGUIObjectByName("resource["+r+"]_icon").sprite = "stretched:session/icons/resources/" + resCode + ".png"; 457 ++r; 458 } 459 horizFitRepeatedObjects ("resource[n]", "n", 0, r); 460 hideRemaining("resource[", r, "]"); 461 451 462 // Hide stuff gaia/observers don't use. 452 Engine.GetGUIObjectByName("food").hidden = !isPlayer; 453 Engine.GetGUIObjectByName("wood").hidden = !isPlayer; 454 Engine.GetGUIObjectByName("stone").hidden = !isPlayer; 455 Engine.GetGUIObjectByName("metal").hidden = !isPlayer; 463 for (let r = 0; r < resources.length; ++r) 464 Engine.GetGUIObjectByName("resource["+r+"]").hidden = !isPlayer; 456 465 Engine.GetGUIObjectByName("population").hidden = !isPlayer; 457 466 Engine.GetGUIObjectByName("civIcon").hidden = !isPlayer; 458 467 Engine.GetGUIObjectByName("diplomacyButton1").hidden = !isPlayer; … … function leaveGame(willRejoin) 558 567 559 568 summary.gameResult = gameResult; 560 569 summary.isReplay = g_IsReplay; 570 summary.resources = GetSimState().resources; 561 571 Engine.SwitchGuiPage("page_summary.xml", summary); 562 572 } 563 573 … … function updateDebug() 981 991 982 992 function updatePlayerDisplay() 983 993 { 984 let playerState = GetSimState().players[g_ViewedPlayer]; 994 let simState = GetSimState(); 995 let playerState = simState.players[g_ViewedPlayer]; 985 996 if (!playerState) 986 997 return; 987 998 988 Engine.GetGUIObjectByName("resourceFood").caption = Math.floor(playerState.resourceCounts.food);989 Engine.GetGUIObjectByName("resourceWood").caption = Math.floor(playerState.resourceCounts.wood);990 Engine.GetGUIObjectByName("resourceStone").caption = Math.floor(playerState.resourceCounts.stone);991 Engine.GetGUIObjectByName("resourceMetal").caption = Math.floor(playerState.resourceCounts.metal); 999 let resCodes = simState.resources.codes; 1000 for (let r = 0; r < resCodes.length; ++r) 1001 Engine.GetGUIObjectByName("resource["+r+"]_count").caption = Math.floor(playerState.resourceCounts[resCodes[r]]); 1002 992 1003 Engine.GetGUIObjectByName("resourcePop").caption = playerState.popCount + "/" + playerState.popLimit; 993 1004 Engine.GetGUIObjectByName("population").tooltip = translate("Population (current / limit)") + "\n" + 994 1005 sprintf(translate("Maximum population: %(popCap)s"), { "popCap": playerState.popMax }); -
binaries/data/mods/public/gui/session/session.xml
diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml index b3cfa1c..2d5ab30 100644
a b 6 6 <script file="gui/common/colorFades.js"/> 7 7 <script file="gui/common/functions_civinfo.js"/> 8 8 <script file="gui/common/functions_global_object.js"/> 9 <script file="gui/common/functions_repeat_positioning.js"/> 9 10 <script file="gui/common/functions_utility.js"/> 10 11 <script file="gui/common/l10n.js"/> 11 12 <script file="gui/common/music.js"/> -
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 c3f49a4..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 <translatableAttribute id="tooltip">Food</translatableAttribute>4 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/food.png" ghost="true"/>5 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceFood"/>6 </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 8dc01ec..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 <translatableAttribute id="tooltip">Metal</translatableAttribute>4 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/metal.png" ghost="true"/>5 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceMetal"/>6 </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 37d08e3..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 <translatableAttribute id="tooltip">Stone</translatableAttribute>4 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/stone.png" ghost="true"/>5 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceStone"/>6 </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 90558af..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 <translatableAttribute id="tooltip">Wood</translatableAttribute>4 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/wood.png" ghost="true"/>5 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceWood"/>6 </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..bcf5784
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 3 <object size="10 0 50%-90-52 100%"> 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..0862bc1 100644
a b 16 16 </object> 17 17 18 18 <object size="180 0 100% 100%"> 19 <repeat count=" 4">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/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..d20686d 100644
a b function calculateUnits(playerState, position) 250 250 251 251 function calculateResources(playerState, position) 252 252 { 253 let type = g_ ResourcesTypes[position];253 let type = g_GameData.resources.codes[position]; 254 254 255 255 return formatIncome( 256 256 playerState.statistics.resourcesGathered[type], … … function calculateTotalResources(playerState) 262 262 let totalGathered = 0; 263 263 let totalUsed = 0; 264 264 265 for (let type of g_ ResourcesTypes)265 for (let type of g_GameData.resources.codes) 266 266 { 267 267 totalGathered += playerState.statistics.resourcesGathered[type]; 268 268 totalUsed += playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type]; … … function calculateResourcesTeam(counters) 330 330 331 331 function calculateResourceExchanged(playerState, position) 332 332 { 333 let type = g_ ResourcesTypes[position];333 let type = g_GameData.resources.codes[position]; 334 334 335 335 return formatIncome( 336 336 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 8fd542d..561cb44 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 ], -
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 6403dd0..d5df321 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"]'; … … function init(data) 199 198 else 200 199 g_Teams = false; 201 200 201 // Resource names and counters 202 let resHeads = []; 203 let tradeHeads = []; 204 let resPanel = g_ScorePanelsData.resources; 205 let tradePanel = g_ScorePanelsData.market; 206 for (let code of g_GameData.resources.codes) 207 { 208 resHeads.push({ 209 "caption": translateWithContext("firstWord", g_GameData.resources.names[code]), 210 "yStart": 34, "width": 100 211 }); 212 resPanel.counters.unshift({"width": 100, "fn": calculateResources, "verticalOffset": 12}); 213 214 tradeHeads.push({ 215 "caption": sprintf( 216 translate("%(resource)s exchanged"), { 217 "resource": translateWithContext("withinSentence", g_GameData.resources.names[code]) 218 }), 219 "yStart": 16, "width": 100 220 }); 221 tradePanel.counters.unshift({"width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12}); 222 } 223 resPanel.headings.splice.apply(resPanel.headings, [1, 0].concat(resHeads)); 224 resPanel.titleHeadings[0].width = (100 * g_GameData.resources.codes.length) + 110; 225 tradePanel.headings.splice.apply(tradePanel.headings, [1, 0].concat(tradeHeads)); 226 202 227 // Erase teams data if teams are not displayed 203 228 if (!g_Teams) 204 229 { -
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 f0fa33f..d108623 100644
a b 109 109 <object name="playerNameHeading" type="text" style="ModernLeftTabLabelText"> 110 110 <translatableAttribute id="caption">Player name</translatableAttribute> 111 111 </object> 112 <repeat var="x" count=" 8">112 <repeat var="x" count="12"> 113 113 <object name="titleHeading[x]" type="text" style="ModernTabLabelText"> 114 114 </object> 115 115 </repeat> 116 <repeat var="x" count=" 8">116 <repeat var="x" count="12"> 117 117 <object name="Heading[x]" type="text" style="ModernTabLabelText"> 118 118 </object> 119 119 </repeat> … … 130 130 </object> 131 131 <object name="playerNamet[i][n]" type="text" size="40 2 208 100%" style="ModernLeftLabelText"/> 132 132 <object name="civIcont[i][n]" type="image" size="208 5 240 37" /> 133 <repeat var="x" count=" 8">133 <repeat var="x" count="12"> 134 134 <object name="valueDataTeam[i][n][x]" type="text" style="ModernTabLabelText"> 135 135 </object> 136 136 </repeat> … … 138 138 </repeat> 139 139 </object> 140 140 <object name="teamHeadingt[i]" type="text" style="ModernLeftTabLabelText"/> 141 <repeat var="x" count=" 8">141 <repeat var="x" count="12"> 142 142 <object name="valueDataTeam[i][x]" type="text" style="ModernTabLabelText"> 143 143 </object> 144 144 </repeat> … … 153 153 </object> 154 154 <object name="playerName[n]" type="text" size="40 2 208 100%" style="ModernLeftLabelText"/> 155 155 <object name="civIcon[n]" type="image" size="208 5 240 37"/> 156 <repeat var="x" count=" 8">156 <repeat var="x" count="12"> 157 157 <object name="valueData[n][x]" type="text" style="ModernTabLabelText"> 158 158 </object> 159 159 </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 768106b..afc3cf0 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 = [ "food", "wood", "stone", "metal" ];12 m.Resources.prototype.types = [ ]; // Gets populated in SharedScript.init 13 13 14 14 m.Resources.prototype.reset = function() 15 15 { -
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 6097da4..deb10b7 100644
a b m.SharedScript = function(settings) 27 27 28 28 // A few notes about these maps. They're updated by checking for "create" and "destroy" events for all resources 29 29 // TODO: change the map when the resource amounts change for at least stone and metal mines. 30 this.resourceMaps = {}; // Contains maps showing the density of wood, stone and metal31 this.CCResourceMaps = {}; // Contains maps showing the density of wood, stone and metal, optimized for CC placement.30 this.resourceMaps = {}; // Contains maps showing the density of resources 31 this.CCResourceMaps = {}; // Contains maps showing the density of resources, optimized for CC placement. 32 32 // Resource maps data. 33 // By how much to divide the resource amount when filling the map (ie a tree having 200 wood is "4").34 this. decreaseFactor = {"wood": 50.0, "stone": 90.0, "metal": 90.0};33 this.decreaseFactor = {}; 34 this.influenceMapGroup = {}; 35 35 }; 36 36 37 37 /** Return a simple object (using no classes etc) that will be serialized into saved games */ … … m.SharedScript.prototype.init = function(state, deserialization) 150 150 this.mapSize = state.mapSize; 151 151 this.gameType = state.gameType; 152 152 this.barterPrices = state.barterPrices; 153 154 m.Resources.prototype.types = state.resources; 153 155 154 156 this.passabilityMap = state.passabilityMap; 155 157 if (this.mapSize % this.passabilityMap.width !== 0) … … m.SharedScript.prototype.init = function(state, deserialization) 187 189 this.accessibility = new m.Accessibility(); 188 190 this.accessibility.init(state, this.terrainAnalyzer); 189 191 190 // defined in TerrainAnalysis.js 192 // By how much to divide the resource amount when filling the map (ie a tree having 200 wood is "4"). 193 for (let res in state.aiResourceAnalysis) 194 { 195 if (!state.aiResourceAnalysis[res]) 196 continue; 197 this.decreaseFactor[res] = state.aiResourceAnalysis[res].decreaseFactor; 198 this.influenceMapGroup[res] = state.aiResourceAnalysis[res].influenceMapGroup; 199 } 200 // defined in terrain-analysis.js 191 201 this.createResourceMaps(this); 192 202 193 203 this.gameState = {}; -
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 f10180d..c840a53 100644
a b m.SharedScript.prototype.createResourceMaps = function(sharedScript) 394 394 this.CCResourceMaps[resource] = new m.Map(sharedScript, "resource"); 395 395 } 396 396 } 397 let cellSize = this.resourceMaps.wood.cellSize; 397 398 398 for (let ent of sharedScript._entities.values()) 399 399 { 400 400 if (ent && ent.position() && ent.resourceSupplyType() && ent.resourceSupplyType().generic !== "treasure") { 401 401 let resource = ent.resourceSupplyType().generic; 402 402 if (!this.resourceMaps[resource]) 403 403 continue; 404 405 let cellSize = this.resourceMaps[resource].cellSize; 404 406 let x = Math.floor(ent.position()[0] / cellSize); 405 407 let z = Math.floor(ent.position()[1] / cellSize); 406 408 let strength = Math.floor(ent.resourceSupplyMax()/this.decreaseFactor[resource]); 407 if ( resource === "wood")409 if (this.influenceMapGroup[resource] === 0) 408 410 { 409 411 this.CCResourceMaps[resource].addInfluence(x, z, 60/cellSize, strength, "constant"); 410 412 this.resourceMaps[resource].addInfluence(x, z, 36/cellSize, strength/2, "constant"); 411 413 this.resourceMaps[resource].addInfluence(x, z, 36/cellSize, strength/2); 412 414 } 413 else if ( resource === "stone" || resource === "metal")415 else if (this.influenceMapGroup[resource] === 1) 414 416 { 415 417 this.CCResourceMaps[resource].addInfluence(x, z, 120/cellSize, strength, "constant"); 416 418 this.resourceMaps[resource].addInfluence(x, z, 48/cellSize, strength/2, "constant"); … … m.SharedScript.prototype.updateResourceMaps = function(sharedScript, events) 439 441 this.CCResourceMaps[resource] = new m.Map(sharedScript, "resource"); 440 442 } 441 443 } 442 let cellSize = this.resourceMaps.wood.cellSize; 444 443 445 // Look for destroy events and subtract the entities original influence from the resourceMap 444 446 // TODO: perhaps do something when dropsites appear/disappear. 445 447 let destEvents = events.Destroy; … … m.SharedScript.prototype.updateResourceMaps = function(sharedScript, events) 455 457 let resource = ent.resourceSupplyType().generic; 456 458 if (!this.resourceMaps[resource]) 457 459 continue; 460 461 let cellSize = this.resourceMaps[resource].cellSize; 458 462 let x = Math.floor(ent.position()[0] / cellSize); 459 463 let z = Math.floor(ent.position()[1] / cellSize); 460 464 let strength = Math.floor(ent.resourceSupplyMax()/this.decreaseFactor[resource]); 461 if ( resource === "wood")465 if (this.influenceMapGroup[resource] === 0) 462 466 { 463 467 this.CCResourceMaps[resource].addInfluence(x, z, 60/cellSize, -strength, "constant"); 464 468 this.resourceMaps[resource].addInfluence(x, z, 36/cellSize, -strength/2, "constant"); 465 469 this.resourceMaps[resource].addInfluence(x, z, 36/cellSize, -strength/2); 466 470 } 467 else if ( resource === "stone" || resource === "metal")471 else if (this.influenceMapGroup[resource] === 1) 468 472 { 469 473 this.CCResourceMaps[resource].addInfluence(x, z, 120/cellSize, -strength, "constant"); 470 474 this.resourceMaps[resource].addInfluence(x, z, 48/cellSize, -strength/2, "constant"); … … m.SharedScript.prototype.updateResourceMaps = function(sharedScript, events) 482 486 let resource = ent.resourceSupplyType().generic; 483 487 if (!this.resourceMaps[resource]) 484 488 continue; 489 490 let cellSize = this.resourceMaps[resource].cellSize; 485 491 let x = Math.floor(ent.position()[0] / cellSize); 486 492 let z = Math.floor(ent.position()[1] / cellSize); 487 493 let strength = Math.floor(ent.resourceSupplyMax()/this.decreaseFactor[resource]); 488 if ( resource === "wood")494 if (this.influenceMapGroup[resource] === 0) 489 495 { 490 496 this.CCResourceMaps[resource].addInfluence(x, z, 60/cellSize, strength, "constant"); 491 497 this.resourceMaps[resource].addInfluence(x, z, 36/cellSize, strength/2, "constant"); 492 498 this.resourceMaps[resource].addInfluence(x, z, 36/cellSize, strength/2); 493 499 } 494 else if ( resource === "stone" || resource === "metal")500 else if (this.influenceMapGroup[resource] === 1) 495 501 { 496 502 this.CCResourceMaps[resource].addInfluence(x, z, 120/cellSize, strength, "constant"); 497 503 this.resourceMaps[resource].addInfluence(x, z, 48/cellSize, strength/2, "constant"); -
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 1e99bd0..866ef8a 100644
a b 1 1 function Cost() {} 2 2 3 Cost.prototype.ResourcesSchema = Resources.BuildSchema("nonNegativeInteger"); 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'><data type='nonNegativeInteger'/></element>" + 28 "<element name='wood'><data type='nonNegativeInteger'/></element>" + 29 "<element name='stone'><data type='nonNegativeInteger'/></element>" + 30 "<element name='metal'><data type='nonNegativeInteger'/></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 let cost = +this.template.Resources[res]; 75 if (resCodes.indexOf(res) < 0) 76 continue; 77 costs[res] = ApplyValueModificationsToTemplate("Cost/Resources/"+res, cost, owner, entityTemplate); 78 } 79 75 80 return costs; 76 81 }; 77 82 -
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 061fd26..b4f35f7 100644
a b GuiInterface.prototype.GetSimulationState = function() 151 151 let cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter); 152 152 ret.barterPrices = cmpBarter.GetPrices(); 153 153 154 // Add Resource Codes, untranslated names and AI Analysis 155 ret.resources = { 156 "codes": Resources.GetCodes(), 157 "names": Resources.GetNames() 158 }; 159 ret.aiResourceAnalysis = {}; 160 for (let res of Resources.GetCodes()) 161 ret.aiResourceAnalysis[res] = Resources.GetResource(res).aiAnalysis || null; 162 154 163 // Add basic statistics to each player 155 164 for (let i = 0; i < numPlayers; ++i) 156 165 { … … GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd) 1244 1253 1245 1254 let result = { 1246 1255 "pieces": [], 1247 "cost": { "food": 0, "wood": 0, "stone": 0, "metal": 0, "population": 0, "populationBonus": 0, "time": 0},1256 "cost": {"population": 0, "populationBonus": 0, "time": 0}, 1248 1257 }; 1249 1258 for (let res of Resources.GetCodes()) 1259 result.cost[res] = 0; 1260 1250 1261 let previewEntities = []; 1251 1262 if (end.pos) 1252 1263 previewEntities = GetWallPlacement(this.placementWallEntities, wallSet, start, end); // see helpers/Walls.js … … GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd) 1520 1531 // copied over, so we need to fetch it from the template instead). 1521 1532 // TODO: we should really use a Cost object or at least some utility functions for this, this is mindless 1522 1533 // boilerplate that's probably duplicated in tons of places. 1523 result.cost.food += tplData.cost.food; 1524 result.cost.wood += tplData.cost.wood; 1525 result.cost.stone += tplData.cost.stone; 1526 result.cost.metal += tplData.cost.metal; 1527 result.cost.population += tplData.cost.population; 1528 result.cost.populationBonus += tplData.cost.populationBonus; 1529 result.cost.time += tplData.cost.time; 1534 let entries = Resources.GetCodes().concat("population", "populationBonus", "time"); 1535 for (let res of entries) 1536 result.cost[res] = tplData.cost[res]; 1530 1537 } 1531 1538 1532 1539 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..772fb05 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 bc98d20..8a0093b 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 let resCodes = Resources.GetCodes(); 43 let tradeProportions = [ 0, 0 ]; 44 tradeProportions[0] = Math.floor(20 / resCodes.length); 45 tradeProportions[1] = 20 - resCodes.length * tradeProportions[0]; 46 let resPos = 0; 47 for (let res of resCodes) 48 { 49 this.resourceCount[res] = 300; 50 this.resourceNames[res] = Resources.GetResource(res).name; 51 let proportion = tradeProportions[0] + ((resPos < tradeProportions[1]) ? 1 : 0); 52 this.tradingGoods.push({ "goods": res, "proba": (proportion * 5) }); 53 ++resPos; 54 } 56 55 }; 57 56 58 57 Player.prototype.SetPlayerID = function(id) … … Player.prototype.UnBlockTraining = function() 197 196 198 197 Player.prototype.SetResourceCounts = function(resources) 199 198 { 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; 199 for (let res in resources) 200 if (this.resourceCount[res]) 201 this.resourceCount[res] = resources[res]; 208 202 }; 209 203 210 204 Player.prototype.GetResourceCounts = function() … … Player.prototype.SubtractResourcesOrNotify = function(amounts) 297 291 298 292 // Subtract the resources 299 293 for (var type in amounts) 300 this.resourceCount[type] -= amounts[type]; 294 if (this.resourceCount[type]) 295 this.resourceCount[type] -= amounts[type]; 301 296 302 297 return true; 303 298 }; … … Player.prototype.SetTradingGoods = function(tradingGoods) 346 341 if (sumProba != 100) // consistency check 347 342 { 348 343 error("Player.js SetTradingGoods: " + uneval(tradingGoods)); 349 tradingGoods = { "food": 20, "wood":20, "stone":30, "metal":30 }; 344 let first = true; 345 for (let res of Resources.GetCodes()) 346 if (first) 347 { 348 tradingGoods[res] = 100; 349 first = false; 350 } 351 else 352 tradingGoods[res] = 0; 350 353 } 351 354 352 355 this.tradingGoods = []; -
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..447b0ff 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 let cost = +template.Cost.Resources[res]; 296 if (resCodes.indexOf(res) < 0) 297 continue; 298 costs[res] = ApplyValueModificationsToTemplate("Cost/Resources/"+res, cost, cmpPlayer.GetPlayerID(), template); 299 totalCosts[res] = Math.floor(count * costs[res]); 300 300 } 301 301 302 302 var population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, cmpPlayer.GetPlayerID(), template); … … ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat 341 341 let techCostMultiplier = this.GetTechCostMultiplier(); 342 342 let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier(); 343 343 344 varcost = {};344 let cost = {}; 345 345 for (let res in template.cost) 346 cost[res] = Math.floor(techCostMultiplier[res] * template.cost[res]); 346 { 347 if (resCodes.indexOf(res) < 0) 348 continue; 349 cost[res] = Math.floor((techCostMultiplier[res] ? techCostMultiplier[res] : 1) * template.cost[res]); 350 } 347 351 348 352 // TrySubtractResources should report error to player (they ran out of resources) 349 353 if (!cmpPlayer.TrySubtractResources(cost)) … … ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat 361 365 "player": cmpPlayer.GetPlayerID(), 362 366 "count": 1, 363 367 "technologyTemplate": templateName, 364 "resources": deepcopy(template.cost), // need to copy to avoid serialization problems368 "resources": cost, 365 369 "productionStarted": false, 366 370 "timeTotal": time*1000, 367 371 "timeRemaining": time*1000, … … ProductionQueue.prototype.RemoveBatch = function(id) 433 437 // Refund the resource cost for this batch 434 438 var totalCosts = {}; 435 439 var cmpStatisticsTracker = QueryPlayerIDInterface(item.player, IID_StatisticsTracker); 436 for each (var r in ["food", "wood", "stone", "metal"])440 for (let r of Resources.GetCodes()) 437 441 { 442 if (!item.resources[r]) 443 continue; 438 444 totalCosts[r] = Math.floor(item.count * item.resources[r]); 439 445 if (cmpStatisticsTracker) 440 446 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 44045c0..f192a4b 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 let types = ApplyValueModificationsToEntity("ResourceDropsite/Types", this.template.Types, this.entity); 32 return types ? types.split(/\s+/) : []; 29 let typesTok = ApplyValueModificationsToEntity("ResourceDropsite/Types", this.template.Types, this.entity); 30 let typesArr = []; 31 let resources = Resources.GetCodes(); 32 33 for (let type of typesTok.split(/\s+/)) 34 if (resources.indexOf(type.toLowerCase()) > -1) 35 typesArr.push(type); 36 37 return typesArr; 33 38 }; 34 39 35 40 /** -
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..eed10e0 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]) < 0)) 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' i n the other case161 * @return 'true' if treasure is successfully gathered and 'false' if not 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..7cc580b 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 = -
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..c36765b
- + 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 "enabled": true 13 } -
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..23a50e5
- + 1 { 2 "code": "metal", 3 "name": "Metal", 4 "subtypes": { 5 "ore": "Ore" 6 }, 7 "truePrice": 100, 8 "aiAnalysis": { 9 "decreaseFactor": 90.0, 10 "influenceMapGroup": 1 11 }, 12 "enabled": true 13 } -
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..a998620
- + 1 { 2 "code": "stone", 3 "name": "Stone", 4 "subtypes": { 5 "rock": "Rock", 6 "ruins": "Ruins" 7 }, 8 "truePrice": 100, 9 "aiAnalysis": { 10 "decreaseFactor": 90.0, 11 "influenceMapGroup": 1 12 }, 13 "enabled": true 14 } -
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..af1e2eb
- + 1 { 2 "code": "wood", 3 "name": "Wood", 4 "subtypes": { 5 "tree": "Tree", 6 "ruins": "Ruins" 7 }, 8 "truePrice": 100, 9 "aiAnalysis": { 10 "decreaseFactor": 50.0, 11 "influenceMapGroup": 0 12 }, 13 "enabled": true 14 } -
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..40f3a51
- + 1 /** 2 * Resource handling helper script 3 * 4 */ 5 6 var Resources = {}; 7 8 /** 9 * Loads all readable resource data into internal stores 10 */ 11 Resources.LoadData = function() 12 { 13 this.resourceData = []; 14 this.resourceCodes = []; 15 16 let jsonFiles = Engine.FindJSONFiles("resources", false); 17 for (let filename of jsonFiles) 18 { 19 let data = Engine.ReadJSONFile("resources/"+filename+".json"); 20 if (!data) 21 continue; 22 23 data.subtypeNames = data.subtypes; 24 data.subtypes = Object.keys(data.subtypes); 25 26 this.resourceData.push(data); 27 if (data.enabled) 28 this.resourceCodes.push(data.code); 29 } 30 }; 31 32 /** 33 * Returns all resource data 34 */ 35 Resources.GetData = function() 36 { 37 if (!this.resourceData) 38 this.LoadData(); 39 40 return this.resourceData.filter((resource) => { return resource.enabled }); 41 }; 42 43 /** 44 * Returns data of a single resource. Only returns data about valid and enabled resources. 45 * 46 * @param type Resource generic type 47 * @return The resource data if found, else false 48 */ 49 Resources.GetResource = function(type) 50 { 51 let data = this.GetData(); 52 type = type.toLowerCase(); 53 54 return data.find((resource) => { return resource.code == type; }) || false; 55 }; 56 57 /** 58 * Returns an array of codes belonging to valid resources 59 * 60 * @return Array of generic resource type codes 61 */ 62 Resources.GetCodes = function() 63 { 64 if (!this.resourceData) 65 this.LoadData(); 66 67 return this.resourceCodes; 68 }; 69 70 /** 71 * Returns an object containing untranslated resource names mapped to 72 * resource codes. Includes subtypes. 73 */ 74 Resources.GetNames = function() 75 { 76 let names = {}; 77 for (let res of this.GetData()) 78 { 79 names[res.code] = res.name; 80 for (let subres of res.subtypes) 81 names[subres] = res.subtypeNames[subres] 82 } 83 return names; 84 }; 85 86 /** 87 * Builds a RelaxRNG schema based on currently valid elements. 88 * 89 * To prevent validation errors, disabled resources are included in the schema. 90 * 91 * @param datatype The datatype of the element 92 * @param additional Array of additional data elements. Time, xp, treasure, etc. 93 * @param subtypes If true, resource subtypes will be included as well. 94 * @return RelaxNG schema string 95 */ 96 Resources.BuildSchema = function(datatype, additional = [], subtypes = false) 97 { 98 if (!datatype) 99 return ""; 100 101 if (!this.resourceData) 102 this.LoadData(); 103 104 switch (datatype) 105 { 106 case "decimal": 107 case "nonNegativeDecimal": 108 case "positiveDecimal": 109 datatype = "<ref name='" + datatype + "'/>"; 110 break; 111 112 default: 113 datatype = "<data type='" + datatype + "'/>"; 114 } 115 116 let resCodes = this.resourceData.map((resource) => { return resource.code }); 117 let schema = "<interleave>"; 118 for (let res of resCodes.concat(additional)) 119 schema += 120 "<optional>" + 121 "<element name='" + res + "'>" + 122 datatype + 123 "</element>" + 124 "</optional>"; 125 126 if (!subtypes) 127 return schema + "</interleave>"; 128 129 for (let res of this.resourceData) 130 for (let subtype of res.subtypes) 131 schema += 132 "<optional>" + 133 "<element name='" + res.code + "." + subtype + "'>" + 134 datatype + 135 "</element>" + 136 "</optional>"; 137 138 if (additional.indexOf("treasure") !== -1) 139 for (let res of resCodes) 140 schema += 141 "<optional>" + 142 "<element name='" + "treasure." + res + "'>" + 143 datatype + 144 "</element>" + 145 "</optional>"; 146 147 return schema + "</interleave>"; 148 } 149 150 /** 151 * Builds the value choices for a RelaxNG `<choice></choice>` object, based on currently valid resources. 152 * 153 * @oaram subtypes If set to true, the choices returned will be resource subtypes, rather than main types 154 * @param treasure If set to true, the pseudo resource 'treasure' (or its subtypes) will be included 155 * @return String of RelaxNG Schema `<choice/>` values. 156 */ 157 Resources.BuildChoicesSchema = function(subtypes = false, treasure = false) 158 { 159 if (!this.resourceData) 160 this.LoadData(); 161 162 let schema = "<choice>"; 163 164 if (!subtypes) 165 { 166 let resCodes = this.resourceData.map((resource) => { return resource.code }); 167 treasure = treasure ? [ "treasure" ] : []; 168 for (let res of resCodes.concat(treasure)) 169 schema += "<value>" + res + "</value>"; 170 } 171 else 172 for (let res of this.resourceData) 173 { 174 for (let subtype of res.subtypes) 175 schema += "<value>" + res.code + "." + subtype + "</value>"; 176 if (treasure) 177 schema += "<value>" + "treasure." + res.code + "</value>"; 178 } 179 180 return schema + "</choice>"; 181 } 182 183 Engine.RegisterGlobal("Resources", Resources);