Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/BuildRestrictions.js
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
* 1. Visibility is not hidden (may be fogged or visible) | * 1. Visibility is not hidden (may be fogged or visible) | ||||
* 2. Check foundation | * 2. Check foundation | ||||
* a. Doesn't obstruct foundation-blocking entities | * a. Doesn't obstruct foundation-blocking entities | ||||
* b. On valid terrain, based on passability class | * b. On valid terrain, based on passability class | ||||
* 3. Territory type is allowed (see note below) | * 3. Territory type is allowed (see note below) | ||||
* 4. Dock is on shoreline and facing into water | * 4. Dock is on shoreline and facing into water | ||||
* 5. Distance constraints satisfied | * 5. Distance constraints satisfied | ||||
* | * | ||||
* Returns result object: | * The function returns undefined on success and | ||||
* { | * a GuiInterface TimeNotification object on failure. | ||||
* "success": true iff the placement is valid, else false | |||||
* "message": message to display in UI for invalid placement, else "" | |||||
* "parameters": parameters to use in the GUI message | |||||
* "translateMessage": always true | |||||
* "translateParameters": list of parameters to translate | |||||
* "pluralMessage": we might return a plural translation instead (optional) | |||||
* "pluralCount": plural translation argument (optional) | |||||
* } | |||||
* | * | ||||
* Note: The entity which is used to check this should be a preview entity | * Note: The entity which is used to check this should be a preview entity | ||||
* (template name should be "preview|"+templateName), as otherwise territory | * (template name should be "preview|"+templateName), as otherwise territory | ||||
* checks for buildings with territory influence will not work as expected. | * checks for buildings with territory influence will not work as expected. | ||||
*/ | */ | ||||
BuildRestrictions.prototype.CheckPlacement = function() | BuildRestrictions.prototype.CheckPlacement = function() | ||||
{ | { | ||||
var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); | var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); | ||||
var name = cmpIdentity ? cmpIdentity.GetGenericName() : "Building"; | var name = cmpIdentity ? cmpIdentity.GetGenericName() : "Building"; | ||||
var result = { | var result = { | ||||
"success": false, | |||||
"message": markForTranslation("%(name)s cannot be built due to unknown error"), | "message": markForTranslation("%(name)s cannot be built due to unknown error"), | ||||
"parameters": { | "parameters": { | ||||
"name": name, | "name": name, | ||||
}, | }, | ||||
"translateMessage": true, | |||||
"translateParameters": ["name"], | "translateParameters": ["name"], | ||||
}; | }; | ||||
// TODO: AI has no visibility info | // TODO: AI has no visibility info | ||||
var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); | var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); | ||||
if (!cmpPlayer.IsAI()) | if (!cmpPlayer.IsAI()) | ||||
{ | { | ||||
// Check whether it's in a visible or fogged region | // Check whether it's in a visible or fogged region | ||||
Show All 28 Lines | BuildRestrictions.prototype.CheckPlacement = function() | ||||
default: | default: | ||||
passClassName = "building-land"; | passClassName = "building-land"; | ||||
} | } | ||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); | var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); | ||||
if (!cmpObstruction) | if (!cmpObstruction) | ||||
return result; // Fail | return result; // Fail | ||||
if (this.template.Category == "Wall") | |||||
{ | |||||
// for walls, only test the center point | // for walls, only test the center point | ||||
var ret = cmpObstruction.CheckFoundation(passClassName, true); | var ret = cmpObstruction.CheckFoundation(passClassName, this.template.Category == "Wall"); | ||||
Stan: let | |||||
} | |||||
else | |||||
{ | |||||
var ret = cmpObstruction.CheckFoundation(passClassName, false); | |||||
} | |||||
if (ret != "success") | if (ret != "success") | ||||
{ | { | ||||
switch (ret) | switch (ret) | ||||
{ | { | ||||
case "fail_error": | case "fail_error": | ||||
case "fail_no_obstruction": | case "fail_no_obstruction": | ||||
error("CheckPlacement: Error returned from CheckFoundation"); | error("CheckPlacement: Error returned from CheckFoundation"); | ||||
break; | break; | ||||
case "fail_obstructs_foundation": | case "fail_obstructs_foundation": | ||||
result.message = markForTranslation("%(name)s cannot be built on another building or resource"); | result.message = markForTranslation("%(name)s cannot be built on another building or resource"); | ||||
break; | break; | ||||
case "fail_terrain_class": | case "fail_terrain_class": | ||||
// TODO: be more specific and/or list valid terrain? | // TODO: be more specific and/or list valid terrain? | ||||
result.message = markForTranslation("%(name)s cannot be built on invalid terrain"); | result.message = markForTranslation("%(name)s cannot be built on invalid terrain"); | ||||
} | } | ||||
return result; // Fail | return result; // Fail | ||||
} | } | ||||
// Check territory restrictions | // Check territory restrictions | ||||
var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); | var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); | ||||
var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); | |||||
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (!(cmpTerritoryManager && cmpPlayer && cmpPosition && cmpPosition.IsInWorld())) | if (!(cmpTerritoryManager && cmpPlayer && cmpPosition && cmpPosition.IsInWorld())) | ||||
return result; // Fail | return result; // Fail | ||||
var pos = cmpPosition.GetPosition2D(); | var pos = cmpPosition.GetPosition2D(); | ||||
var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); | var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); | ||||
var isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y); | var isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y); | ||||
var isOwn = tileOwner == cmpPlayer.GetPlayerID(); | var isOwn = tileOwner == cmpPlayer.GetPlayerID(); | ||||
Show All 29 Lines | BuildRestrictions.prototype.CheckPlacement = function() | ||||
{ | { | ||||
// consider everything else enemy territory | // consider everything else enemy territory | ||||
if (!this.HasTerritory("enemy")) | if (!this.HasTerritory("enemy")) | ||||
// Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.". | // Translation: territoryType being displayed in a translated sentence in the form: "House cannot be built in %(territoryType)s territory.". | ||||
invalidTerritory = markForTranslationWithContext("Territory type", "enemy"); | invalidTerritory = markForTranslationWithContext("Territory type", "enemy"); | ||||
} | } | ||||
if (invalidTerritory) | if (invalidTerritory) | ||||
{ | return { | ||||
result.message = markForTranslation("%(name)s cannot be built in %(territoryType)s territory. Valid territories: %(validTerritories)s"); | "message": markForTranslation("%(name)s cannot be built in %(territoryType)s territory. Valid territories: %(validTerritories)s"), | ||||
result.translateParameters.push("territoryType"); | "translateParameters": [ | ||||
result.translateParameters.push("validTerritories"); | "name", | ||||
result.parameters.territoryType = {"context": "Territory type", "message": invalidTerritory}; | "territoryType", | ||||
"validTerritories" | |||||
], | |||||
"parameters": { | |||||
"name": name, | |||||
"territoryType": { | |||||
"context": "Territory type", | |||||
"message": invalidTerritory | |||||
}, | |||||
// gui code will join this array to a string | // gui code will join this array to a string | ||||
result.parameters.validTerritories = {"context": "Territory type list", "list": this.GetTerritories()}; | "validTerritories": { | ||||
return result; // Fail | "context": "Territory type list", | ||||
"list": this.GetTerritories() | |||||
} | |||||
} | } | ||||
}; | |||||
// Check special requirements | // Check special requirements | ||||
if (this.template.PlacementType == "shore") | if (this.template.PlacementType == "shore") | ||||
{ | { | ||||
if (!cmpObstruction.CheckShorePlacement()) | if (!cmpObstruction.CheckShorePlacement()) | ||||
{ | { | ||||
result.message = markForTranslation("%(name)s must be built on a valid shoreline"); | result.message = markForTranslation("%(name)s must be built on a valid shoreline"); | ||||
return result; // Fail | return result; // Fail | ||||
} | } | ||||
} | } | ||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
let templateName = cmpTemplateManager.GetCurrentTemplateName(this.entity); | let templateName = cmpTemplateManager.GetCurrentTemplateName(this.entity); | ||||
let template = cmpTemplateManager.GetTemplate(removeFiltersFromTemplateName(templateName)); | let template = cmpTemplateManager.GetTemplate(removeFiltersFromTemplateName(templateName)); | ||||
// Check distance restriction | // Check distance restriction | ||||
if (this.template.Distance) | if (this.template.Distance) | ||||
{ | { | ||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); | let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); | ||||
var cat = this.template.Distance.FromClass; | let category = this.template.Distance.FromClass; | ||||
var filter = function(id) | let filter = (id) => { | ||||
{ | let cmpIdentity = Engine.QueryInterface(id, IID_Identity); | ||||
var cmpIdentity = Engine.QueryInterface(id, IID_Identity); | return cmpIdentity.GetClassesList().indexOf(category) != -1; | ||||
return cmpIdentity.GetClassesList().indexOf(cat) > -1; | |||||
}; | }; | ||||
if (this.template.Distance.MinDistance !== undefined) | if (this.template.Distance.MinDistance !== undefined) | ||||
{ | { | ||||
let minDistance = ApplyValueModificationsToTemplate("BuildRestrictions/Distance/MinDistance", +this.template.Distance.MinDistance, cmpPlayer.GetPlayerID(), template); | let minDistance = ApplyValueModificationsToTemplate("BuildRestrictions/Distance/MinDistance", +this.template.Distance.MinDistance, cmpPlayer.GetPlayerID(), template); | ||||
if (cmpRangeManager.ExecuteQuery(this.entity, 0, minDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).some(filter)) | if (cmpRangeManager.ExecuteQuery(this.entity, 0, minDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).some(filter)) | ||||
{ | return { | ||||
let result = markForPluralTranslation( | "message": markForPluralTranslation( | ||||
"%(name)s too close to a %(category)s, must be at least %(distance)s meter away", | "%(name)s too close to a %(category)s, must be at least %(distance)s meter away", | ||||
"%(name)s too close to a %(category)s, must be at least %(distance)s meters away", | "%(name)s too close to a %(category)s, must be at least %(distance)s meters away", | ||||
minDistance); | minDistance), | ||||
"parameters": { | |||||
result.success = false; | |||||
result.translateMessage = true; | |||||
result.parameters = { | |||||
"name": name, | "name": name, | ||||
"category": cat, | "category": category, | ||||
"distance": minDistance | "distance": minDistance | ||||
}, | |||||
"translateParameters": ["name", "category"] | |||||
}; | }; | ||||
result.translateParameters = ["name", "category"]; | |||||
return result; // Fail | |||||
} | |||||
} | } | ||||
if (this.template.Distance.MaxDistance !== undefined) | if (this.template.Distance.MaxDistance !== undefined) | ||||
{ | { | ||||
let maxDistance = ApplyValueModificationsToTemplate("BuildRestrictions/Distance/MaxDistance", +this.template.Distance.MaxDistance, cmpPlayer.GetPlayerID(), template); | let maxDistance = ApplyValueModificationsToTemplate("BuildRestrictions/Distance/MaxDistance", +this.template.Distance.MaxDistance, cmpPlayer.GetPlayerID(), template); | ||||
if (!cmpRangeManager.ExecuteQuery(this.entity, 0, maxDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).some(filter)) | if (!cmpRangeManager.ExecuteQuery(this.entity, 0, maxDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).some(filter)) | ||||
{ | return { | ||||
let result = markForPluralTranslation( | "message": | ||||
markForPluralTranslation( | |||||
"%(name)s too far from a %(category)s, must be within %(distance)s meter", | "%(name)s too far from a %(category)s, must be within %(distance)s meter", | ||||
"%(name)s too far from a %(category)s, must be within %(distance)s meters", | "%(name)s too far from a %(category)s, must be within %(distance)s meters", | ||||
maxDistance); | maxDistance), | ||||
"parameters": { | |||||
result.success = false; | |||||
result.translateMessage = true; | |||||
result.parameters = { | |||||
"name": name, | "name": name, | ||||
"category": cat, | "category": category, | ||||
"distance": maxDistance | "distance": maxDistance | ||||
}, | |||||
"translateParameters": ["name", "category"] | |||||
}; | }; | ||||
result.translateParameters = ["name", "category"]; | |||||
return result; // Fail | |||||
} | |||||
} | } | ||||
} | } | ||||
// Success | // Success | ||||
result.success = true; | return undefined; | ||||
result.message = ""; | |||||
return result; | |||||
}; | }; | ||||
BuildRestrictions.prototype.GetCategory = function() | BuildRestrictions.prototype.GetCategory = function() | ||||
{ | { | ||||
return this.template.Category; | return this.template.Category; | ||||
}; | }; | ||||
BuildRestrictions.prototype.GetTerritories = function() | BuildRestrictions.prototype.GetTerritories = function() | ||||
Show All 19 Lines |
Wildfire Games · Phabricator
let