Ticket #3934: resource_agnostic-v5.patch
File resource_agnostic-v5.patch, 89.9 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/gui/common/functions_repeat_positioning.js
1 /** 2 * Horizontally fit objects repeated with the `<repeat>` tag within a parent object 3 * 4 * @param basename The base name of the object, such as "object[n]" or "object[a]_sub[b]" 5 * @param splitvar The var identifying the repeat count, without the square brackets 6 * @param margin The gap, in px, between the repeated objects 7 * @param limit The number of elements to fit 8 * @return The number of elements affected 9 */ 10 function horizFitRepeatedObjects(basename, splitvar="n", margin=0, limit=0) 11 { 12 basename = basename.split("["+splitvar+"]", 2); 13 14 let objObj; 15 if (limit == 0) 16 do 17 { 18 objObj = Engine.GetGUIObjectByName(basename.join("["+ ++limit +"]")); 19 } 20 while (objObj) 21 22 for (let c = 0; c < limit; ++c) 23 { 24 objObj = Engine.GetGUIObjectByName(basename.join("["+ c +"]")); 25 let objSize = objObj.size; 26 objSize.rleft = c * (100/limit); 27 objSize.rright = (c+1) * (100/limit); 28 objSize.right = -margin; 29 objObj.size = objSize; 30 } 31 32 return limit; 33 } 34 35 /** 36 * Hide all repeated elements after a certain index 37 * 38 * @param prefix The part of the element name preceeding the index 39 * @param idx The index from which to start 40 * @param prefix The part of the element name after the index 41 */ 42 function hideRemaining(prefix, idx, suffix) 43 { 44 while (true) 45 { 46 let obj = Engine.GetGUIObjectByName(prefix + idx + suffix); 47 if (!obj) 48 return; 49 obj.hidden = true; 50 ++idx; 51 } 52 } -
binaries/data/mods/public/gui/common/l10n.js
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 /** 76 8 * Format resource amounts to proper english and translate (for example: "200 food, 100 wood, and 300 metal"). 77 9 */ … … function getLocalizedResourceAmounts(res 79 11 { 80 12 let amounts = Object.keys(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) 88 20 { 89 21 let lastAmount = amounts.pop(); -
binaries/data/mods/public/gui/common/setup_resources.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 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 /> 29 29 </setup> -
binaries/data/mods/public/gui/common/tooltips.js
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 10 1 const g_TooltipTextFormats = { 11 2 "unit": ['[font="sans-10"][color="orange"]', '[/color][/font]'], 12 3 "header": ['[font="sans-bold-13"]', '[/font]'], 13 4 "body": ['[font="sans-13"]', '[/font]'], 14 5 "comma": ['[font="sans-12"]', '[/font]'] … … const g_DamageTypes = { 25 16 "hack": translate("Hack"), 26 17 "pierce": translate("Pierce"), 27 18 "crush": translate("Crush"), 28 19 }; 29 20 21 function costIcon(resource) 22 { 23 return '[icon="icon_' + resource + "]'; 24 } 25 30 26 function bodyFont(text) 31 27 { 32 28 return g_TooltipTextFormats.body[0] + text + g_TooltipTextFormats.body[1]; 33 29 } 34 30 … … function getEntityCostComponentsTooltipS 321 317 if (template.cost.time) 322 318 totalCosts.time = Math.ceil(template.cost.time * (entity ? Engine.GuiInterfaceCall("GetBatchTime", { "entity": entity, "batchSize": trainNum }) : 1)); 323 319 324 320 let costs = []; 325 321 326 for (let type in g_CostDisplayIcons) 327 if (totalCosts[type]) 322 for (let c in template.cost) 323 { 324 if (c == "populationBonus" || !totalCosts[c]) 325 continue; 326 327 if (typeof GetSimState === "undefined" || GetSimState().resources.codes.indexOf(c) > -1 || c === "time") 328 328 costs.push(sprintf(translate("%(component)s %(cost)s"), { 329 "component": g_CostDisplayIcons[type],330 "cost": totalCosts[ type]329 "component": costIcon(c), 330 "cost": totalCosts[c] 331 331 })); 332 } 332 333 333 334 return costs; 334 335 } 335 336 function getGatherTooltip(template) 336 337 { … … function getGatherTooltip(template) 340 341 return sprintf(translate("%(label)s %(details)s"), { 341 342 "label": headerFont(translate("Gather Rates:")), 342 343 "details": 343 344 Object.keys(template.gather).map( 344 345 type => sprintf(translate("%(resourceIcon)s %(rate)s"), { 345 "resourceIcon": g_CostDisplayIcons[type],346 "resourceIcon": costIcon(type), 346 347 "rate": template.gather[type] 347 348 }) 348 349 ).join(" ") 349 350 }); 350 351 } … … function getWallPieceTooltip(wallTypes) 389 390 if (sameTypes) 390 391 for (let resource in resourceCount) 391 392 // Translation: This string is part of the resources cost string on 392 393 // the tooltip for wall structures. 393 394 out.push(sprintf(translate("%(resourceIcon)s %(minimum)s to %(resourceIcon)s %(maximum)s"), { 394 "resourceIcon": g_CostDisplayIcons[resource],395 "resourceIcon": costIcon(resource), 395 396 "minimum": Math.min.apply(Math, resourceCount[resource]), 396 397 "maximum": Math.max.apply(Math, resourceCount[resource]) 397 398 })); 398 399 else 399 400 for (let i = 0; i < wallTypes.length; ++i) … … function getNeededResourcesTooltip(resou 452 453 return ""; 453 454 454 455 let formatted = []; 455 456 for (let resource in resources) 456 457 formatted.push(sprintf(translate("%(component)s %(cost)s"), { 457 "component": '[font="sans-12"]' + g_CostDisplayIcons[resource]+ '[/font]',458 "component": '[font="sans-12"]' + costIcon(resource) + '[/font]', 458 459 "cost": resources[resource] 459 460 })); 460 461 461 462 return '\n[font="sans-bold-13"][color="red"]' + translate("Insufficient resources:") + '[/color][/font]\n' + formatted.join(" "); 462 463 } -
binaries/data/mods/public/gui/session/diplomacy_window.xml
9 9 <object type="text" style="TitleText" size="50%-96 -16 50%+96 16"> 10 10 <translatableAttribute id="caption">Diplomacy</translatableAttribute> 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"> 18 18 <translatableAttribute id="caption">Civilization</translatableAttribute> 19 19 </object> … … 21 21 <translatableAttribute id="caption">Team</translatableAttribute> 22 22 </object> 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> 42 42 <object size="32 64 100%-32 384"> 43 43 <repeat count="16"> … … 46 46 <object name="diplomacyPlayerCiv[n]" size="150 0 250 100%" type="text" style="chatPanel" ghost="true"/> 47 47 <object name="diplomacyPlayerTeam[n]" size="250 0 300 100%" type="text" style="chatPanel" ghost="true"/> 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"> 70 65 <object name="diplomacyAttackRequestImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/attack-request.png" ghost="true"/> 71 66 </object> -
binaries/data/mods/public/gui/session/menu.js
const MENU_TOP = MENU_BOTTOM - END_MENU_ 20 20 const INITIAL_MENU_POSITION = "100%-164 " + MENU_TOP + " 100% " + MENU_BOTTOM; 21 21 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 31 28 // Shown in the trade dialog. 32 29 const g_IdleTraderTextColor = "orange"; … … function openDiplomacy() 235 232 return; 236 233 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; 243 241 let rowsize = onesize.bottom - onesize.top; 244 242 … … function openDiplomacy() 253 251 diplomacyFormatStanceButtons(i, myself || playerInactive || isCeasefireActive || g_Players[g_ViewedPlayer].teamsLocked); 254 252 diplomacyFormatTributeButtons(i, myself || playerInactive); 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) 262 266 { 263 267 // Apply offset … … function diplomacyFormatStanceButtons(i, 303 307 } 304 308 } 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); 320 ++r; 312 321 if (hidden) 313 322 continue; 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; 321 330 return function() { 322 331 let isBatchTrainPressed = Engine.HotkeyIsPressed("session.masstribute"); … … function diplomacyFormatTributeButtons(i 325 334 inputState = INPUT_MASSTRIBUTING; 326 335 multiplier += multiplier == 1 ? 4 : 5; 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 351 360 function diplomacyFormatAttackRequestButton(i, hidden) 352 361 { … … function openTrade() 396 405 button[res].up.hidden = !controlsPlayer(g_ViewedPlayer) || res == selec || proba[res] == 100 || proba[selec] == 0; 397 406 button[res].dn.hidden = !controlsPlayer(g_ViewedPlayer) || res == selec || proba[res] == 0 || proba[selec] == 100; 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}); 435 440 } 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){ 443 448 return function() { 444 449 proba[resource] += Math.min(STEP, proba[selec]); 445 450 proba[selec] -= Math.min(STEP, proba[selec]); 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){ 453 458 return function() { 454 459 proba[selec] += Math.min(STEP, proba[resource]); 455 460 proba[resource] -= Math.min(STEP, proba[resource]); 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 463 468 let traderNumber = Engine.GuiInterfaceCall("GetTraderNumber", g_ViewedPlayer); 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) 471 482 { 472 483 let active = traderNumber.landTrader.trading; -
binaries/data/mods/public/gui/session/selection_details.js
function layoutSelectionMultiple() 11 11 } 12 12 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 23 21 function updateGarrisionHealthBar(entState, selection) 24 22 { … … function displayMultiple(selection) 393 391 } 394 392 395 393 let numberOfUnits = Engine.GetGUIObjectByName("numberOfUnits"); 396 394 numberOfUnits.caption = selection.length; 397 395 numberOfUnits.tooltip = Object.keys(totalResourcesCarried).map(res => 398 g_CostDisplayIcons[res]+ totalResourcesCarried[res]396 costIcon(res) + totalResourcesCarried[res] 399 397 ).join(" "); 400 398 401 399 // Unhide Details Area 402 400 Engine.GetGUIObjectByName("detailsAreaMultiple").hidden = false; 403 401 Engine.GetGUIObjectByName("detailsAreaSingle").hidden = true; -
binaries/data/mods/public/gui/session/selection_panels.js
32 32 let g_AvailableFormations = new Map(); 33 33 let g_FormationsInfo = new Map(); 34 34 35 35 let g_SelectionPanels = {}; 36 36 37 let g_BarterSell; 38 37 39 g_SelectionPanels.Alert = { 38 40 "getMaxNumberOfItems": function() 39 41 { 40 42 return 2; 41 43 }, … … g_SelectionPanels.Alert = { 85 87 }; 86 88 87 89 g_SelectionPanels.Barter = { 88 90 "getMaxNumberOfItems": function() 89 91 { 90 return 4;92 return 8; 91 93 }, 92 94 "rowLength": 4, 93 95 "getItems": function(unitEntState, selection) 94 96 { 95 97 if (!unitEntState.barterMarket) 96 98 return []; 97 // ["food", "wood", "stone", "metal"] 98 return BARTER_RESOURCES; 99 return GetSimState().resources.codes; 99 100 }, 100 101 "setupButton": function(data) 101 102 { 102 103 // data.item is the resource name in this case 103 104 let button = {}; … … g_SelectionPanels.Barter = { 113 114 114 115 let amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL; 115 116 if (Engine.HotkeyIsPressed("session.massbarter")) 116 117 amountToSell *= BARTER_BUNCH_MULTIPLIER; 117 118 119 if (!g_BarterSell) 120 g_BarterSell = GetSimState().resources.codes[0]; 121 118 122 amount.Sell.caption = "-" + amountToSell; 119 123 let prices = data.unitEntState.barterMarket.prices; 120 124 amount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[data.item] * amountToSell); 121 125 122 let resource = getLocalizedResourceName( data.item, "withinSentence");126 let resource = getLocalizedResourceName(GetSimState().resources.names[data.item], "firstWord"); 123 127 button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), { "resource": resource }); 124 128 button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), { "resource": resource }); 125 129 126 130 button.Sell.onPress = function() { 127 131 g_BarterSell = data.item; … … g_SelectionPanels.Barter = { 162 166 button.Buy.hidden = isSelected; 163 167 button.Buy.enabled = controlsPlayer(data.unitEntState.player); 164 168 button.Sell.hidden = false; 165 169 selectionIcon.hidden = !isSelected; 166 170 167 setPanelObjectPosition(button.Sell, data.i, data.rowLength); 168 setPanelObjectPosition(button.Buy, data.i + data.rowLength, data.rowLength); 171 let sellPos = data.i + (data.i >= data.rowLength ? data.rowLength : 0); 172 let buyPos = data.i + data.rowLength * (data.i >= data.rowLength ? 2 : 1); 173 setPanelObjectPosition(button.Sell, sellPos, data.rowLength); 174 setPanelObjectPosition(button.Buy, buyPos, data.rowLength); 169 175 return true; 170 176 } 171 177 }; 172 178 173 179 g_SelectionPanels.Command = { … … g_SelectionPanels.Queue = { 647 653 let tooltip = getEntityNames(template); 648 654 if (data.item.neededSlots) 649 655 { 650 656 tooltip += "\n[color=\"red\"]" + translate("Insufficient population capacity:") + "\n[/color]"; 651 657 tooltip += sprintf(translate("%(population)s %(neededSlots)s"), { 652 "population": g_CostDisplayIcons.population,658 "population": costIcon("population"), 653 659 "neededSlots": data.item.neededSlots 654 660 }); 655 661 } 656 662 data.button.tooltip = tooltip; 657 663 … … g_SelectionPanels.Selection = { 874 880 } 875 881 876 882 let tooltip = getEntityNames(template); 877 883 if (data.carried) 878 884 tooltip += "\n" + Object.keys(data.carried).map(res => 879 g_CostDisplayIcons[res]+ data.carried[res]885 costIcon(res) + data.carried[res] 880 886 ).join(" "); 881 887 data.button.tooltip = tooltip; 882 888 883 889 data.countDisplay.caption = ents.length || ""; 884 890 -
binaries/data/mods/public/gui/session/selection_panels_helpers.js
1 1 const BARTER_RESOURCE_AMOUNT_TO_SELL = 100; 2 2 const BARTER_BUNCH_MULTIPLIER = 5; 3 const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];4 3 const BARTER_ACTIONS = ["Sell", "Buy"]; 5 4 const GATE_ACTIONS = ["lock", "unlock"]; 6 5 7 // upgrade constants8 6 const UPGRADING_NOT_STARTED = -2; 9 7 const UPGRADING_CHOSEN_OTHER = -1; 10 8 11 // ==============================================12 // BARTER HELPERS13 // Resources to sell on barter panel14 var g_BarterSell = "food";15 16 9 function canMoveSelectionIntoFormation(formationTemplate) 17 10 { 18 11 if (!(formationTemplate in g_canMoveIntoFormation)) 19 12 { 20 13 g_canMoveIntoFormation[formationTemplate] = Engine.GuiInterfaceCall("CanMoveEntsIntoFormation", { -
binaries/data/mods/public/gui/session/selection_panels_left/barter_panel.xml
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
function updateTopPanel() 464 464 let civName = g_CivData[g_Players[g_ViewedPlayer].civ].Name; 465 465 Engine.GetGUIObjectByName("civIcon").sprite = "stretched:" + g_CivData[g_Players[g_ViewedPlayer].civ].Emblem; 466 466 Engine.GetGUIObjectByName("civIconOverlay").tooltip = sprintf(translate("%(civ)s - Structure Tree"), { "civ": civName }); 467 467 } 468 468 469 let resources = GetSimState().resources; 470 let r = 0; 471 for (let resCode of resources.codes) 472 { 473 Engine.GetGUIObjectByName("resource["+r+"]").tooltip = getLocalizedResourceName(resources.names[resCode], "firstWord"); 474 Engine.GetGUIObjectByName("resource["+r+"]_icon").sprite = "stretched:session/icons/resources/" + resCode + ".png"; 475 ++r; 476 } 477 horizFitRepeatedObjects ("resource[n]", "n", 0, r); 478 hideRemaining("resource[", r, "]"); 479 469 480 // Hide stuff gaia/observers don't use. 470 Engine.GetGUIObjectByName("food").hidden = !isPlayer; 471 Engine.GetGUIObjectByName("wood").hidden = !isPlayer; 472 Engine.GetGUIObjectByName("stone").hidden = !isPlayer; 473 Engine.GetGUIObjectByName("metal").hidden = !isPlayer; 481 for (let r = 0; r < resources.codes.length; ++r) 482 Engine.GetGUIObjectByName("resource["+r+"]").hidden = !isPlayer; 474 483 Engine.GetGUIObjectByName("population").hidden = !isPlayer; 475 484 Engine.GetGUIObjectByName("civIcon").hidden = !isPlayer; 476 485 Engine.GetGUIObjectByName("diplomacyButton1").hidden = !isPlayer; 477 486 Engine.GetGUIObjectByName("tradeButton1").hidden = !isPlayer; 478 487 Engine.GetGUIObjectByName("observerText").hidden = isPlayer; … … function updateDebug() 933 942 debug.caption = text.replace(/\[/g, "\\["); 934 943 } 935 944 936 945 function updatePlayerDisplay() 937 946 { 938 let playerState = GetSimState().players[g_ViewedPlayer]; 947 let simState = GetSimState(); 948 let playerState = simState.players[g_ViewedPlayer]; 939 949 if (!playerState) 940 950 return; 941 951 942 Engine.GetGUIObjectByName("resourceFood").caption = Math.floor(playerState.resourceCounts.food);943 Engine.GetGUIObjectByName("resourceWood").caption = Math.floor(playerState.resourceCounts.wood);944 Engine.GetGUIObjectByName("resourceStone").caption = Math.floor(playerState.resourceCounts.stone);945 Engine.GetGUIObjectByName("resourceMetal").caption = Math.floor(playerState.resourceCounts.metal); 952 let resCodes = simState.resources.codes; 953 for (let r = 0; r < resCodes.length; ++r) 954 Engine.GetGUIObjectByName("resource["+r+"]_count").caption = Math.floor(playerState.resourceCounts[resCodes[r]]); 955 946 956 Engine.GetGUIObjectByName("resourcePop").caption = playerState.popCount + "/" + playerState.popLimit; 947 957 Engine.GetGUIObjectByName("population").tooltip = translate("Population (current / limit)") + "\n" + 948 958 sprintf(translate("Maximum population: %(popCap)s"), { "popCap": playerState.popMax }); 949 959 950 960 g_IsTrainingBlocked = playerState.trainingBlocked; -
binaries/data/mods/public/gui/session/session.xml
4 4 5 5 <script file="gui/common/color.js"/> 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"/> 12 13 <script file="gui/common/network.js"/> 13 14 <script file="gui/common/settings.js"/> -
binaries/data/mods/public/gui/session/top_panel/resource_population.xml
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> -
binaries/data/mods/public/gui/session/trade_window.xml
14 14 <object name="tradeHeader" size="0 0 180 100%" type="text" style="ModernLabelText" text_align="left" ghost="true"> 15 15 <translatableAttribute id="caption">Trading goods selection:</translatableAttribute> 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"/> 23 23 <object name="tradeResourceSelection[n]" type="image" sprite="stretched:session/icons/corners.png" ghost="true"/> 24 24 <object name="tradeResourceText[n]" type="text" style="ModernLabelText" ghost="true"/> -
binaries/data/mods/public/gui/summary/counters.js
function calculateUnits(playerState, pos 248 248 playerState.statistics.enemyUnitsKilled[type]); 249 249 } 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], 257 257 playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type]); 258 258 } … … function calculateResources(playerState, 260 260 function calculateTotalResources(playerState) 261 261 { 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]; 269 269 } 270 270 … … function calculateResourcesTeam(counters 328 328 } 329 329 } 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], 337 337 playerState.statistics.resourcesSold[type]); 338 338 } -
binaries/data/mods/public/gui/summary/layout.js
var g_ScorePanelsData = { 90 90 "teamCounterFn": calculateUnitsTeam 91 91 }, 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)"), 102 98 { 103 99 "sent": g_IncomeColor + translate("Sent") + '[/color]', … … var g_ScorePanelsData = { 119 115 "yStart": 16, 120 116 "width": (100 * 4 + 110) 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 }, 131 123 { "width": 100, "fn": calculateLootCollected, "verticalOffset": 12 } 132 124 ], 133 125 "teamCounterFn": calculateResourcesTeam 134 126 }, 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 ], 154 138 "teamCounterFn": calculateMarketTeam 155 139 }, -
binaries/data/mods/public/gui/summary/summary.js
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; 5 5 6 6 const g_PlayerBoxYSize = 40; … … const g_LostColor = '[color="255 213 213 15 15 const g_KilledColor = '[color="196 198 255"]'; 16 16 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"]'; 24 23 const g_OutcomeColor = '[color="255 213 213"]'; 25 24 … … function init(data) 240 239 g_Teams = false; // Each player has his own team. Displaying teams makes no sense. 241 240 } 242 241 else 243 242 g_Teams = false; 244 243 244 // Resource names and counters 245 let resHeads = []; 246 let tradeHeads = []; 247 let resPanel = g_ScorePanelsData.resources; 248 let tradePanel = g_ScorePanelsData.market; 249 for (let code of g_GameData.resources.codes) 250 { 251 resHeads.push({ 252 "caption": translateWithContext("firstWord", g_GameData.resources.names[code]), 253 "yStart": 34, "width": 100 254 }); 255 resPanel.counters.unshift({"width": 100, "fn": calculateResources, "verticalOffset": 12}); 256 257 tradeHeads.push({ 258 "caption": sprintf( 259 translate("%(resource)s exchanged"), { 260 "resource": translateWithContext("withinSentence", g_GameData.resources.names[code]) 261 }), 262 "yStart": 16, "width": 100 263 }); 264 tradePanel.counters.unshift({"width": 100, "fn": calculateResourceExchanged, "verticalOffset": 12}); 265 } 266 resPanel.headings.splice.apply(resPanel.headings, [1, 0].concat(resHeads)); 267 resPanel.titleHeadings[0].width = (100 * g_GameData.resources.codes.length) + 110; 268 tradePanel.headings.splice.apply(tradePanel.headings, [1, 0].concat(tradeHeads)); 269 245 270 // Erase teams data if teams are not displayed 246 271 if (!g_Teams) 247 272 { 248 273 for (let p = 0; p < g_PlayerCount; ++p) 249 274 g_GameData.sim.playerStates[p+1].team = -1; -
binaries/data/mods/public/gui/summary/summary.xml
101 101 <object name="generalPanel" type="image" sprite="ForegroundBody" size="20 120 100%-20 100%-54"> 102 102 <object size="0 0 100% 100%-50"> 103 103 <object name="playerNameHeading" type="text" style="ModernLeftTabLabelText"> 104 104 <translatableAttribute id="caption">Player name</translatableAttribute> 105 105 </object> 106 <repeat var="x" count=" 8">106 <repeat var="x" count="12"> 107 107 <object name="titleHeading[x]" type="text" style="ModernTabLabelText"> 108 108 </object> 109 109 </repeat> 110 <repeat var="x" count=" 8">110 <repeat var="x" count="12"> 111 111 <object name="Heading[x]" type="text" style="ModernTabLabelText"> 112 112 </object> 113 113 </repeat> 114 114 </object> 115 115 … … 122 122 <object type="image" sprite="ForegroundBox" size="10 9 34 33"> 123 123 <object name="playerColorBoxt[i][n]" type="image" size="2 2 22 22"/> 124 124 </object> 125 125 <object name="playerNamet[i][n]" type="text" size="40 2 208 100%" style="ModernLeftLabelText"/> 126 126 <object name="civIcont[i][n]" type="image" size="208 5 240 37" /> 127 <repeat var="x" count=" 8">127 <repeat var="x" count="12"> 128 128 <object name="valueDataTeam[i][n][x]" type="text" style="ModernTabLabelText"> 129 129 </object> 130 130 </repeat> 131 131 </object> 132 132 </repeat> 133 133 </object> 134 134 <object name="teamHeadingt[i]" type="text" style="ModernLeftTabLabelText"/> 135 <repeat var="x" count=" 8">135 <repeat var="x" count="12"> 136 136 <object name="valueDataTeam[i][x]" type="text" style="ModernTabLabelText"> 137 137 </object> 138 138 </repeat> 139 139 </object> 140 140 </repeat> … … 145 145 <object type="image" sprite="ForegroundBox" size="10 9 34 33"> 146 146 <object name="playerColorBox[n]" type="image" size="2 2 22 22"/> 147 147 </object> 148 148 <object name="playerName[n]" type="text" size="40 2 208 100%" style="ModernLeftLabelText"/> 149 149 <object name="civIcon[n]" type="image" size="208 5 240 37"/> 150 <repeat var="x" count=" 8">150 <repeat var="x" count="12"> 151 151 <object name="valueData[n][x]" type="text" style="ModernTabLabelText"> 152 152 </object> 153 153 </repeat> 154 154 </object> 155 155 </repeat> -
binaries/data/mods/public/l10n/messages.json
287 287 }, 288 288 "translate": {} 289 289 } 290 290 } 291 291 }, 292 292 { 293 293 "extractor": "json", 294 294 "filemasks": [ 295 295 "gui/credits/texts/**.json" 296 296 ], 297 297 "options": { … … 560 560 "keywords": [ 561 561 "name", 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 }, 568 594 { 569 595 "output": "public-maps.pot", -
binaries/data/mods/public/simulation/components/Cost.js
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>" + 6 8 "<Population>1</Population>" + 7 9 "<PopulationBonus>15</PopulationBonus>" + … … Cost.prototype.Schema = 17 19 "<data type='nonNegativeInteger'/>" + 18 20 "</element>" + 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() 35 32 { 36 33 this.populationCost = +this.template.Population; … … Cost.prototype.GetResourceCosts = functi 68 65 let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 69 66 let entityTemplateName = cmpTemplateManager.GetCurrentTemplateName(this.entity); 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 78 83 Cost.prototype.OnOwnershipChanged = function(msg) 79 84 { -
binaries/data/mods/public/simulation/components/GuiInterface.js
GuiInterface.prototype.GetSimulationStat 149 149 150 150 // Add bartering prices 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 { 157 166 let playerEnt = cmpPlayerManager.GetPlayerByID(i); 158 167 let cmpPlayerStatisticsTracker = Engine.QueryInterface(playerEnt, IID_StatisticsTracker); … … GuiInterface.prototype.SetWallPlacementP 1265 1274 // -------------------------------------------------------------------------------- 1266 1275 // calculate wall placement and position preview entities 1267 1276 1268 1277 let result = { 1269 1278 "pieces": [], 1270 "cost": { "food": 0, "wood": 0, "stone": 0, "metal": 0, "population": 0, "populationBonus": 0, "time": 0},1279 "cost": {"population": 0, "populationBonus": 0, "time": 0}, 1271 1280 }; 1272 1281 for (let res of Resources.GetCodes()) 1282 result.cost[res] = 0; 1283 1273 1284 let previewEntities = []; 1274 1285 if (end.pos) 1275 1286 previewEntities = GetWallPlacement(this.placementWallEntities, wallSet, start, end); // see helpers/Walls.js 1276 1287 1277 1288 // For wall placement, we may (and usually do) need to have wall pieces overlap each other more than would … … GuiInterface.prototype.SetWallPlacementP 1541 1552 1542 1553 // grab the cost of this wall piece and add it up (note; preview entities don't have their Cost components 1543 1554 // copied over, so we need to fetch it from the template instead). 1544 1555 // TODO: we should really use a Cost object or at least some utility functions for this, this is mindless 1545 1556 // boilerplate that's probably duplicated in tons of places. 1546 result.cost.food += tplData.cost.food; 1547 result.cost.wood += tplData.cost.wood; 1548 result.cost.stone += tplData.cost.stone; 1549 result.cost.metal += tplData.cost.metal; 1550 result.cost.population += tplData.cost.population; 1551 result.cost.populationBonus += tplData.cost.populationBonus; 1552 result.cost.time += tplData.cost.time; 1557 let entries = Resources.GetCodes().concat("population", "populationBonus", "time"); 1558 for (let res of entries) 1559 result.cost[res] = tplData.cost[res]; 1553 1560 } 1554 1561 1555 1562 let canAfford = true; 1556 1563 let cmpPlayer = QueryPlayerIDInterface(player, IID_Player); 1557 1564 if (cmpPlayer && cmpPlayer.GetNeededResources(result.cost)) -
binaries/data/mods/public/simulation/components/Loot.js
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 22 15 Loot.prototype.GetXp = function() 23 16 { 24 17 return +(this.template.xp || 0); 25 18 }; 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
Player.prototype.Init = function() 16 16 this.color = { "r": 0.0, "g": 0.0, "b": 0.0, "a": 1.0 }; 17 17 this.popUsed = 0; // population of units owned or trained by this player 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" 36 26 this.diplomacy = []; // array of diplomatic stances for this player with respect to other players (including gaia and self) 37 27 this.sharedDropsites = false; … … Player.prototype.Init = function() 42 32 this.gatherRateMultiplier = 1; 43 33 this.tradeRateMultiplier = 1; 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) 59 58 { 60 59 this.playerID = id; … … Player.prototype.UnBlockTraining = funct 195 194 this.trainingBlocked = false; 196 195 }; 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() 211 205 { 212 206 return this.resourceCount; … … Player.prototype.SubtractResourcesOrNoti 295 289 return false; 296 290 } 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 }; 304 299 305 300 Player.prototype.TrySubtractResources = function(amounts) … … Player.prototype.SetTradingGoods = funct 344 339 for (var resource in tradingGoods) 345 340 sumProba += tradingGoods[resource]; 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 = []; 353 356 for (var resource in tradingGoods) 354 357 this.tradingGoods.push( {"goods": resource, "proba": tradingGoods[resource]} ); -
binaries/data/mods/public/simulation/components/ProductionQueue.js
1 1 var g_ProgressInterval = 1000; 2 2 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>" + 9 11 "<BatchTimeModifier>0.7</BatchTimeModifier>" + 10 12 "<Entities datatype='tokens'>" + … … ProductionQueue.prototype.Schema = 29 31 "</attribute>" + 30 32 "<text/>" + 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() 44 40 { 45 41 this.nextID = 1; … … ProductionQueue.prototype.IsTechnologyRe 258 254 ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadata) 259 255 { 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 { 267 264 268 265 if (type == "unit") … … ProductionQueue.prototype.AddBatch = fun 291 288 var costs = {}; 292 289 var totalCosts = {}; 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); 303 303 304 304 // TrySubtractResources should report error to player (they ran out of resources) … … ProductionQueue.prototype.AddBatch = fun 339 339 return; 340 340 var cmpPlayer = QueryOwnerInterface(this.entity); 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)) 350 354 return; 351 355 … … ProductionQueue.prototype.AddBatch = fun 359 363 this.queue.push({ 360 364 "id": this.nextID++, 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, 368 372 }); 369 373 … … ProductionQueue.prototype.RemoveBatch = 431 435 } 432 436 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]); 441 447 } 442 448 -
binaries/data/mods/public/simulation/components/ResourceDropsite.js
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>" + 16 13 "<element name='Sharable' a:help='Allows allies to use this entity.'>" + 17 14 "<data type='boolean'/>" + … … ResourceDropsite.prototype.Init = functi 22 19 this.sharable = this.template.Sharable == "true"; 23 20 this.shared = this.sharable; 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 /** 36 41 * Returns whether this dropsite accepts the given generic type of resource. 37 42 */ -
binaries/data/mods/public/simulation/components/ResourceGatherer.js
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>" + 6 9 "<MaxDistance>2.0</MaxDistance>" + 7 10 "<BaseSpeed>1.0</BaseSpeed>" + … … ResourceGatherer.prototype.Schema = 23 26 "</element>" + 24 27 "<element name='BaseSpeed' a:help='Base resource-gathering rate (in resource units per second)'>" + 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() 60 38 { 61 39 this.carrying = {}; // { generic type: integer amount currently carried } … … ResourceGatherer.prototype.RecalculateGa 135 113 this.baseSpeed = multiplier * ApplyValueModificationsToEntity("ResourceGatherer/BaseSpeed", +this.template.BaseSpeed, this.entity); 136 114 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 } 143 127 144 128 this.capacities = {}; … … ResourceGatherer.prototype.GetRange = fu 172 156 // maybe this should depend on the unit or target or something? 173 157 }; 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 { 181 165 let cmpResourceSupply = Engine.QueryInterface(target, IID_ResourceSupply); 182 166 let type = cmpResourceSupply.GetType(); -
binaries/data/mods/public/simulation/components/ResourceSupply.js
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>" + 6 8 "<Amount>1000</Amount>" + 7 9 "<Type>food.meat</Type>" + … … ResourceSupply.prototype.Schema = 10 12 "<data type='boolean'/>" + 11 13 "</element>" + 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'/>" + 35 22 "</element>" + 36 23 "<optional>" + … … ResourceSupply.prototype.Init = function 43 30 { 44 31 // Current resource amount (non-negative) 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() 61 55 { 62 56 return this.infinite; -
binaries/data/mods/public/simulation/components/ResourceTrickle.js
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'/>" + 31 12 "</element>"; 32 13 … … ResourceTrickle.prototype.GetTimer = fun 43 24 return interval; 44 25 }; 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 }; 54 40 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
StatisticsTracker.prototype.Init = funct 103 103 "total": 0 104 104 }; 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; 135 123 this.tradeIncome = 0; 136 124 this.treasuresCollected = 0; … … StatisticsTracker.prototype.IncreaseReso 345 333 * @param type Generic type of resource (string) 346 334 * @param amount Amount of resource, which should be added (integer) 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() 354 343 { 355 344 ++this.treasuresCollected; -
binaries/data/mods/public/simulation/components/Trader.js
2 2 // resources a trader gets 3 3 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 = 13 10 "<a:help>Lets the unit generate resouces while moving between markets (or docks in case of water trading).</a:help>" + 14 11 "<a:example>" + -
binaries/data/mods/public/simulation/data/resources/food.json
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 } -
binaries/data/mods/public/simulation/data/resources/metal.json
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 } -
binaries/data/mods/public/simulation/data/resources/stone.json
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 } -
binaries/data/mods/public/simulation/data/resources/wood.json
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 } -
binaries/data/mods/public/simulation/helpers/Resources.js
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);