Changeset View
Standalone View
binaries/data/mods/public/simulation/components/GuiInterface.js
function GuiInterface() {} | function GuiInterface() {} | ||||
GuiInterface.prototype.Schema = | GuiInterface.prototype.Schema = | ||||
"<a:component type='system'/><empty/>"; | "<a:component type='system'/><empty/>"; | ||||
GuiInterface.prototype.Serialize = function() | GuiInterface.prototype.Serialize = function() | ||||
{ | { | ||||
// This component isn't network-synchronised for the biggest part | // This component isn't network-synchronised for the biggest part, | ||||
// So most of the attributes shouldn't be serialized | // so most of the attributes shouldn't be serialised. | ||||
// Return an object with a small selection of deterministic data | // Return an object with a small selection of deterministic data. | ||||
Nescio: -ized
Usually I don't mind whether people use American or British spelling in comments, but… | |||||
Done Inline ActionsTransltable strings are in en-US, code had been changed from british english to US english too, for example in the colour -> color commits. And Amour had always been planned to be renamed to Armor. elexis: Transltable strings are in en-US, code had been changed from british english to US english too… | |||||
return { | return { | ||||
"timeNotifications": this.timeNotifications, | "timeNotifications": this.timeNotifications, | ||||
"timeNotificationID": this.timeNotificationID | "timeNotificationID": this.timeNotificationID | ||||
}; | }; | ||||
}; | }; | ||||
GuiInterface.prototype.Deserialize = function(data) | GuiInterface.prototype.Deserialize = function(data) | ||||
{ | { | ||||
Show All 38 Lines | GuiInterface.prototype.GetSimulationState = function() | ||||
}; | }; | ||||
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); | let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); | ||||
for (let i = 0; i < numPlayers; ++i) | for (let i = 0; i < numPlayers; ++i) | ||||
{ | { | ||||
let cmpPlayer = QueryPlayerIDInterface(i); | let cmpPlayer = QueryPlayerIDInterface(i); | ||||
let cmpPlayerEntityLimits = QueryPlayerIDInterface(i, IID_EntityLimits); | let cmpPlayerEntityLimits = QueryPlayerIDInterface(i, IID_EntityLimits); | ||||
// Work out what phase we are in | // Work out which phase we are in. | ||||
Done Inline Actionswhich Nescio: which | |||||
let phase = ""; | let phase = ""; | ||||
let cmpTechnologyManager = QueryPlayerIDInterface(i, IID_TechnologyManager); | let cmpTechnologyManager = QueryPlayerIDInterface(i, IID_TechnologyManager); | ||||
if (cmpTechnologyManager) | if (cmpTechnologyManager) | ||||
{ | |||||
if (cmpTechnologyManager.IsTechnologyResearched("phase_city")) | if (cmpTechnologyManager.IsTechnologyResearched("phase_city")) | ||||
phase = "city"; | phase = "city"; | ||||
else if (cmpTechnologyManager.IsTechnologyResearched("phase_town")) | else if (cmpTechnologyManager.IsTechnologyResearched("phase_town")) | ||||
phase = "town"; | phase = "town"; | ||||
else if (cmpTechnologyManager.IsTechnologyResearched("phase_village")) | else if (cmpTechnologyManager.IsTechnologyResearched("phase_village")) | ||||
phase = "village"; | phase = "village"; | ||||
} | |||||
Done Inline ActionsBetter keep the brackets for this type of expression, otherwise diff seems OK. nani: Better keep the brackets for this type of expression, otherwise diff seems OK. | |||||
Done Inline Actionsyes, better to keep them here for readability and not exactly one line code Silier: yes, better to keep them here for readability and not exactly one line code | |||||
// store player ally/neutral/enemy data as arrays | // Store player ally/neutral/enemy data as arrays. | ||||
let allies = []; | let allies = []; | ||||
let mutualAllies = []; | let mutualAllies = []; | ||||
let neutrals = []; | let neutrals = []; | ||||
let enemies = []; | let enemies = []; | ||||
for (let j = 0; j < numPlayers; ++j) | for (let j = 0; j < numPlayers; ++j) | ||||
{ | { | ||||
allies[j] = cmpPlayer.IsAlly(j); | allies[j] = cmpPlayer.IsAlly(j); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | GuiInterface.prototype.GetSimulationState = function() | ||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
if (cmpRangeManager) | if (cmpRangeManager) | ||||
ret.circularMap = cmpRangeManager.GetLosCircular(); | ret.circularMap = cmpRangeManager.GetLosCircular(); | ||||
let cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); | let cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); | ||||
if (cmpTerrain) | if (cmpTerrain) | ||||
ret.mapSize = cmpTerrain.GetMapSize(); | ret.mapSize = cmpTerrain.GetMapSize(); | ||||
// Add timeElapsed | // Add timeElapsed. | ||||
SilierUnsubmitted Done Inline Actionsi think we do not really need this type of comments Silier: i think we do not really need this type of comments
One can read what we are doing by reading… | |||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
ret.timeElapsed = cmpTimer.GetTime(); | ret.timeElapsed = cmpTimer.GetTime(); | ||||
// Add ceasefire info | // Add ceasefire info. | ||||
let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager); | let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager); | ||||
if (cmpCeasefireManager) | if (cmpCeasefireManager) | ||||
{ | { | ||||
ret.ceasefireActive = cmpCeasefireManager.IsCeasefireActive(); | ret.ceasefireActive = cmpCeasefireManager.IsCeasefireActive(); | ||||
ret.ceasefireTimeRemaining = ret.ceasefireActive ? cmpCeasefireManager.GetCeasefireStartedTime() + cmpCeasefireManager.GetCeasefireTime() - ret.timeElapsed : 0; | ret.ceasefireTimeRemaining = ret.ceasefireActive ? cmpCeasefireManager.GetCeasefireStartedTime() + cmpCeasefireManager.GetCeasefireTime() - ret.timeElapsed : 0; | ||||
} | } | ||||
// Add cinema path info | // Add cinema path info. | ||||
let cmpCinemaManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CinemaManager); | let cmpCinemaManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CinemaManager); | ||||
if (cmpCinemaManager) | if (cmpCinemaManager) | ||||
ret.cinemaPlaying = cmpCinemaManager.IsPlaying(); | ret.cinemaPlaying = cmpCinemaManager.IsPlaying(); | ||||
// Add the game type and allied victory | // Add the game type and allied victory. | ||||
let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); | let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); | ||||
ret.victoryConditions = cmpEndGameManager.GetVictoryConditions(); | ret.victoryConditions = cmpEndGameManager.GetVictoryConditions(); | ||||
ret.alliedVictory = cmpEndGameManager.GetAlliedVictory(); | ret.alliedVictory = cmpEndGameManager.GetAlliedVictory(); | ||||
// Add basic statistics to each player | // Add basic statistics to each player. | ||||
for (let i = 0; i < numPlayers; ++i) | for (let i = 0; i < numPlayers; ++i) | ||||
{ | { | ||||
let cmpPlayerStatisticsTracker = QueryPlayerIDInterface(i, IID_StatisticsTracker); | let cmpPlayerStatisticsTracker = QueryPlayerIDInterface(i, IID_StatisticsTracker); | ||||
if (cmpPlayerStatisticsTracker) | if (cmpPlayerStatisticsTracker) | ||||
ret.players[i].statistics = cmpPlayerStatisticsTracker.GetBasicStatistics(); | ret.players[i].statistics = cmpPlayerStatisticsTracker.GetBasicStatistics(); | ||||
} | } | ||||
return ret; | return ret; | ||||
}; | }; | ||||
/** | /** | ||||
* Returns global information about the current game state, plus statistics. | * Returns global information about the current game state, plus statistics. | ||||
* This is used by the GUI at the end of a game, in the summary screen. | * This is used by the GUI at the end of a game, in the summary screen. | ||||
* Note: Amongst statistics, the team exploration map percentage is computed from | * Note: Amongst statistics, the team exploration map percentage is computed from | ||||
* scratch, so the extended simulation state should not be requested too often. | * scratch, so the extended simulation state should not be requested too often. | ||||
*/ | */ | ||||
GuiInterface.prototype.GetExtendedSimulationState = function() | GuiInterface.prototype.GetExtendedSimulationState = function() | ||||
{ | { | ||||
// Get basic simulation info | // Get basic simulation info. | ||||
let ret = this.GetSimulationState(); | let ret = this.GetSimulationState(); | ||||
// Add statistics to each player | // Add statistics to each player. | ||||
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); | let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); | ||||
for (let i = 0; i < numPlayers; ++i) | for (let i = 0; i < numPlayers; ++i) | ||||
{ | { | ||||
let cmpPlayerStatisticsTracker = QueryPlayerIDInterface(i, IID_StatisticsTracker); | let cmpPlayerStatisticsTracker = QueryPlayerIDInterface(i, IID_StatisticsTracker); | ||||
if (cmpPlayerStatisticsTracker) | if (cmpPlayerStatisticsTracker) | ||||
ret.players[i].sequences = cmpPlayerStatisticsTracker.GetSequences(); | ret.players[i].sequences = cmpPlayerStatisticsTracker.GetSequences(); | ||||
} | } | ||||
Show All 18 Lines | |||||
{ | { | ||||
if (!this.miragedEntities[player]) | if (!this.miragedEntities[player]) | ||||
this.miragedEntities[player] = []; | this.miragedEntities[player] = []; | ||||
this.miragedEntities[player].push({ "entity": entity, "newentity": mirage }); | this.miragedEntities[player].push({ "entity": entity, "newentity": mirage }); | ||||
}; | }; | ||||
/** | /** | ||||
* Get common entity info, often used in the gui | * Get common entity info, often used in the gui. | ||||
*/ | */ | ||||
GuiInterface.prototype.GetEntityState = function(player, ent) | GuiInterface.prototype.GetEntityState = function(player, ent) | ||||
{ | { | ||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
// All units must have a template; if not then it's a nonexistent entity id | // All units must have a template; if not then it's a nonexistent entity id. | ||||
let template = cmpTemplateManager.GetCurrentTemplateName(ent); | let template = cmpTemplateManager.GetCurrentTemplateName(ent); | ||||
if (!template) | if (!template) | ||||
return null; | return null; | ||||
let ret = { | let ret = { | ||||
"id": ent, | "id": ent, | ||||
"player": INVALID_PLAYER, | "player": INVALID_PLAYER, | ||||
"template": template | "template": template | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | GuiInterface.prototype.GetEntityState = function(player, ent) | ||||
let cmpPack = Engine.QueryInterface(ent, IID_Pack); | let cmpPack = Engine.QueryInterface(ent, IID_Pack); | ||||
if (cmpPack) | if (cmpPack) | ||||
ret.pack = { | ret.pack = { | ||||
"packed": cmpPack.IsPacked(), | "packed": cmpPack.IsPacked(), | ||||
"progress": cmpPack.GetProgress(), | "progress": cmpPack.GetProgress(), | ||||
}; | }; | ||||
var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); | let cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); | ||||
Done Inline Actionslet? Nescio: `let`? | |||||
if (cmpUpgrade) | if (cmpUpgrade) | ||||
ret.upgrade = { | ret.upgrade = { | ||||
"upgrades": cmpUpgrade.GetUpgrades(), | "upgrades": cmpUpgrade.GetUpgrades(), | ||||
"progress": cmpUpgrade.GetProgress(), | "progress": cmpUpgrade.GetProgress(), | ||||
"template": cmpUpgrade.GetUpgradingTo() | "template": cmpUpgrade.GetUpgradingTo() | ||||
}; | }; | ||||
let cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); | let cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); | ||||
Show All 35 Lines | GuiInterface.prototype.GetEntityState = function(player, ent) | ||||
let cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder); | let cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder); | ||||
if (cmpGarrisonHolder) | if (cmpGarrisonHolder) | ||||
ret.garrisonHolder = { | ret.garrisonHolder = { | ||||
"entities": cmpGarrisonHolder.GetEntities(), | "entities": cmpGarrisonHolder.GetEntities(), | ||||
"buffHeal": cmpGarrisonHolder.GetHealRate(), | "buffHeal": cmpGarrisonHolder.GetHealRate(), | ||||
"allowedClasses": cmpGarrisonHolder.GetAllowedClasses(), | "allowedClasses": cmpGarrisonHolder.GetAllowedClasses(), | ||||
"capacity": cmpGarrisonHolder.GetCapacity(), | "capacity": cmpGarrisonHolder.GetCapacity(), | ||||
"garrisonedEntitiesCount": cmpGarrisonHolder.GetGarrisonedEntitiesCount() | "garrisonedEntitiesCount": cmpGarrisonHolder.GetGarrisonedEntitiesCount() | ||||
SilierUnsubmitted Done Inline Actionsplease make this kind of object style consistent and put , after last key-value, Silier: please make this kind of object style consistent and put `,` after last key-value,
it also… | |||||
SilierUnsubmitted Done Inline Actionsmake it consistent on function level, if count of both occurrences is even, make it consistent on file level :) Silier: make it consistent on function level, if count of both occurrences is even, make it consistent… | |||||
}; | }; | ||||
ret.canGarrison = !!Engine.QueryInterface(ent, IID_Garrisonable); | ret.canGarrison = !!Engine.QueryInterface(ent, IID_Garrisonable); | ||||
let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | ||||
if (cmpUnitAI) | if (cmpUnitAI) | ||||
ret.unitAI = { | ret.unitAI = { | ||||
"state": cmpUnitAI.GetCurrentState(), | "state": cmpUnitAI.GetCurrentState(), | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | for (let type of types) | ||||
ret.attack[type].maxRange = range.max; | ret.attack[type].maxRange = range.max; | ||||
let timers = cmpAttack.GetTimers(type); | let timers = cmpAttack.GetTimers(type); | ||||
ret.attack[type].prepareTime = timers.prepare; | ret.attack[type].prepareTime = timers.prepare; | ||||
ret.attack[type].repeatTime = timers.repeat; | ret.attack[type].repeatTime = timers.repeat; | ||||
if (type != "Ranged") | if (type != "Ranged") | ||||
{ | { | ||||
// not a ranged attack, set some defaults | // Not a ranged attack, set some defaults. | ||||
ret.attack[type].elevationBonus = 0; | ret.attack[type].elevationBonus = 0; | ||||
ret.attack[type].elevationAdaptedRange = ret.attack.maxRange; | ret.attack[type].elevationAdaptedRange = ret.attack.maxRange; | ||||
continue; | continue; | ||||
} | } | ||||
ret.attack[type].elevationBonus = range.elevationBonus; | ret.attack[type].elevationBonus = range.elevationBonus; | ||||
// For units, take the range in front of it, no spread. So angle = 0. | |||||
if (cmpUnitAI && cmpPosition && cmpPosition.IsInWorld()) | if (cmpUnitAI && cmpPosition && cmpPosition.IsInWorld()) | ||||
{ | |||||
// For units, take the range in front of it, no spread. So angle = 0 | |||||
ret.attack[type].elevationAdaptedRange = cmpRangeManager.GetElevationAdaptedRange(cmpPosition.GetPosition(), cmpPosition.GetRotation(), range.max, range.elevationBonus, 0); | ret.attack[type].elevationAdaptedRange = cmpRangeManager.GetElevationAdaptedRange(cmpPosition.GetPosition(), cmpPosition.GetRotation(), range.max, range.elevationBonus, 0); | ||||
} | // For buildings, take the average elevation around it. So angle = 2*pi. | ||||
else if(cmpPosition && cmpPosition.IsInWorld()) | else if(cmpPosition && cmpPosition.IsInWorld()) | ||||
{ | |||||
// For buildings, take the average elevation around it. So angle = 2*pi | |||||
ret.attack[type].elevationAdaptedRange = cmpRangeManager.GetElevationAdaptedRange(cmpPosition.GetPosition(), cmpPosition.GetRotation(), range.max, range.elevationBonus, 2*Math.PI); | ret.attack[type].elevationAdaptedRange = cmpRangeManager.GetElevationAdaptedRange(cmpPosition.GetPosition(), cmpPosition.GetRotation(), range.max, range.elevationBonus, 2 * Math.PI); | ||||
Done Inline ActionsShouldn't it be 2 * Math.PI? Nescio: Shouldn't it be `2 * Math.PI`? | |||||
} | // Not in world, set a default? | ||||
Done Inline Actions2 * Pi ? (spaces) Stan: 2 * Pi ? (spaces) | |||||
else | else | ||||
Done Inline ActionsCould merge the two statements, and ternary for cmpUnit ai like so: ret.attack[type].elevationAdaptedRange = cmpRangeManager.GetElevationAdaptedRange(cmpPosition.GetPosition(), cmpPosition.GetRotation(), range.max, range.elevationBonus, cmpUnitAI ? 0 : 2 * Math.PI); One might also wonder why not checking for buildingAI. Stan: Could merge the two statements, and ternary for cmpUnit ai like so:
```lang=js
ret.attack… | |||||
{ | |||||
// not in world, set a default? | |||||
ret.attack[type].elevationAdaptedRange = ret.attack.maxRange; | ret.attack[type].elevationAdaptedRange = ret.attack.maxRange; | ||||
} | } | ||||
} | } | ||||
} | |||||
let cmpArmour = Engine.QueryInterface(ent, IID_DamageReceiver); | let cmpArmour = Engine.QueryInterface(ent, IID_DamageReceiver); | ||||
if (cmpArmour) | if (cmpArmour) | ||||
ret.armour = cmpArmour.GetArmourStrengths(); | ret.armour = cmpArmour.GetArmourStrengths(); | ||||
let cmpBuildingAI = Engine.QueryInterface(ent, IID_BuildingAI); | let cmpBuildingAI = Engine.QueryInterface(ent, IID_BuildingAI); | ||||
if (cmpBuildingAI) | if (cmpBuildingAI) | ||||
ret.buildingAI = { | ret.buildingAI = { | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | let pos = { | ||||
"x": cmd.x, | "x": cmd.x, | ||||
"y": cmpTerrain.GetGroundLevel(cmd.x, cmd.z), | "y": cmpTerrain.GetGroundLevel(cmd.x, cmd.z), | ||||
"z": cmd.z | "z": cmd.z | ||||
}; | }; | ||||
let elevationBonus = cmd.elevationBonus || 0; | let elevationBonus = cmd.elevationBonus || 0; | ||||
let range = cmd.range; | let range = cmd.range; | ||||
return cmpRangeManager.GetElevationAdaptedRange(pos, rot, range, elevationBonus, 2*Math.PI); | return cmpRangeManager.GetElevationAdaptedRange(pos, rot, range, elevationBonus, 2 * Math.PI); | ||||
Done Inline Actionsidem Nescio: idem | |||||
}; | }; | ||||
GuiInterface.prototype.GetTemplateData = function(player, templateName) | GuiInterface.prototype.GetTemplateData = function(player, templateName) | ||||
{ | { | ||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
let template = cmpTemplateManager.GetTemplate(templateName); | let template = cmpTemplateManager.GetTemplate(templateName); | ||||
if (!template) | if (!template) | ||||
Show All 20 Lines | GuiInterface.prototype.IsTechnologyResearched = function(player, data) | ||||
let cmpTechnologyManager = QueryPlayerIDInterface(data.player || player, IID_TechnologyManager); | let cmpTechnologyManager = QueryPlayerIDInterface(data.player || player, IID_TechnologyManager); | ||||
if (!cmpTechnologyManager) | if (!cmpTechnologyManager) | ||||
return false; | return false; | ||||
return cmpTechnologyManager.IsTechnologyResearched(data.tech); | return cmpTechnologyManager.IsTechnologyResearched(data.tech); | ||||
}; | }; | ||||
// Checks whether the requirements for this technology have been met | // Checks whether the requirements for this technology have been met. | ||||
SilierUnsubmitted Done Inline ActionsDoxygen Silier: Doxygen | |||||
GuiInterface.prototype.CheckTechnologyRequirements = function(player, data) | GuiInterface.prototype.CheckTechnologyRequirements = function(player, data) | ||||
{ | { | ||||
let cmpTechnologyManager = QueryPlayerIDInterface(data.player || player, IID_TechnologyManager); | let cmpTechnologyManager = QueryPlayerIDInterface(data.player || player, IID_TechnologyManager); | ||||
if (!cmpTechnologyManager) | if (!cmpTechnologyManager) | ||||
return false; | return false; | ||||
return cmpTechnologyManager.CanResearch(data.tech); | return cmpTechnologyManager.CanResearch(data.tech); | ||||
}; | }; | ||||
// Returns technologies that are being actively researched, along with | // Returns technologies that are being actively researched, along with | ||||
// which entity is researching them and how far along the research is. | // which entity is researching them and how far along the research is. | ||||
SilierUnsubmitted Done Inline ActionsDoxygen Silier: Doxygen | |||||
GuiInterface.prototype.GetStartedResearch = function(player) | GuiInterface.prototype.GetStartedResearch = function(player) | ||||
{ | { | ||||
let cmpTechnologyManager = QueryPlayerIDInterface(player, IID_TechnologyManager); | let cmpTechnologyManager = QueryPlayerIDInterface(player, IID_TechnologyManager); | ||||
if (!cmpTechnologyManager) | if (!cmpTechnologyManager) | ||||
return {}; | return {}; | ||||
let ret = {}; | let ret = {}; | ||||
for (let tech of cmpTechnologyManager.GetStartedTechs()) | for (let tech of cmpTechnologyManager.GetStartedTechs()) | ||||
Show All 9 Lines | for (let tech of cmpTechnologyManager.GetStartedTechs()) | ||||
{ | { | ||||
ret[tech].progress = 0; | ret[tech].progress = 0; | ||||
ret[tech].timeRemaining = 0; | ret[tech].timeRemaining = 0; | ||||
} | } | ||||
} | } | ||||
return ret; | return ret; | ||||
}; | }; | ||||
// Returns the battle state of the player. | // Returns the battle state of the player. | ||||
SilierUnsubmitted Done Inline ActionsDoxygen Silier: Doxygen | |||||
GuiInterface.prototype.GetBattleState = function(player) | GuiInterface.prototype.GetBattleState = function(player) | ||||
{ | { | ||||
let cmpBattleDetection = QueryPlayerIDInterface(player, IID_BattleDetection); | let cmpBattleDetection = QueryPlayerIDInterface(player, IID_BattleDetection); | ||||
if (!cmpBattleDetection) | if (!cmpBattleDetection) | ||||
return false; | return false; | ||||
return cmpBattleDetection.GetState(); | return cmpBattleDetection.GetState(); | ||||
}; | }; | ||||
// Returns a list of ongoing attacks against the player. | // Returns a list of ongoing attacks against the player. | ||||
SilierUnsubmitted Done Inline ActionsDoxygen Silier: Doxygen | |||||
GuiInterface.prototype.GetIncomingAttacks = function(player) | GuiInterface.prototype.GetIncomingAttacks = function(player) | ||||
{ | { | ||||
return QueryPlayerIDInterface(player, IID_AttackDetection).GetIncomingAttacks(); | return QueryPlayerIDInterface(player, IID_AttackDetection).GetIncomingAttacks(); | ||||
}; | }; | ||||
// Used to show a red square over GUI elements you can't yet afford. | // Used to show a red square over GUI elements you can't yet afford. | ||||
SilierUnsubmitted Done Inline ActionsDoxygen Silier: Doxygen | |||||
GuiInterface.prototype.GetNeededResources = function(player, data) | GuiInterface.prototype.GetNeededResources = function(player, data) | ||||
{ | { | ||||
return QueryPlayerIDInterface(data.player || player).GetNeededResources(data.cost); | return QueryPlayerIDInterface(data.player || player).GetNeededResources(data.cost); | ||||
}; | }; | ||||
/** | /** | ||||
* State of the templateData (player dependent): true when some template values have been modified | * State of the templateData (player dependent): true when some template values have been modified | ||||
* and need to be reloaded by the gui. | * and need to be reloaded by the gui. | ||||
Show All 20 Lines | |||||
* so they should allways be added and deleted in a deterministic way. | * so they should allways be added and deleted in a deterministic way. | ||||
*/ | */ | ||||
GuiInterface.prototype.AddTimeNotification = function(notification, duration = 10000) | GuiInterface.prototype.AddTimeNotification = function(notification, duration = 10000) | ||||
{ | { | ||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
notification.endTime = duration + cmpTimer.GetTime(); | notification.endTime = duration + cmpTimer.GetTime(); | ||||
notification.id = ++this.timeNotificationID; | notification.id = ++this.timeNotificationID; | ||||
// Let all players and observers receive the notification by default | // Let all players and observers receive the notification by default. | ||||
if (!notification.players) | if (!notification.players) | ||||
{ | { | ||||
notification.players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers(); | notification.players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers(); | ||||
notification.players[0] = -1; | notification.players[0] = -1; | ||||
} | } | ||||
this.timeNotifications.push(notification); | this.timeNotifications.push(notification); | ||||
this.timeNotifications.sort((n1, n2) => n2.endTime - n1.endTime); | this.timeNotifications.sort((n1, n2) => n2.endTime - n1.endTime); | ||||
cmpTimer.SetTimeout(this.entity, IID_GuiInterface, "DeleteTimeNotification", duration, this.timeNotificationID); | cmpTimer.SetTimeout(this.entity, IID_GuiInterface, "DeleteTimeNotification", duration, this.timeNotificationID); | ||||
return this.timeNotificationID; | return this.timeNotificationID; | ||||
}; | }; | ||||
GuiInterface.prototype.DeleteTimeNotification = function(notificationID) | GuiInterface.prototype.DeleteTimeNotification = function(notificationID) | ||||
{ | { | ||||
this.timeNotifications = this.timeNotifications.filter(n => n.id != notificationID); | this.timeNotifications = this.timeNotifications.filter(n => n.id != notificationID); | ||||
}; | }; | ||||
GuiInterface.prototype.GetTimeNotifications = function(player) | GuiInterface.prototype.GetTimeNotifications = function(player) | ||||
{ | { | ||||
let time = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).GetTime(); | let time = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).GetTime(); | ||||
// filter on players and time, since the delete timer might be executed with a delay | // Filter on players and time, since the delete timer might be executed with a delay. | ||||
return this.timeNotifications.filter(n => n.players.indexOf(player) != -1 && n.endTime > time); | return this.timeNotifications.filter(n => n.players.indexOf(player) != -1 && n.endTime > time); | ||||
}; | }; | ||||
GuiInterface.prototype.PushNotification = function(notification) | GuiInterface.prototype.PushNotification = function(notification) | ||||
{ | { | ||||
if (!notification.type || notification.type == "text") | if (!notification.type || notification.type == "text") | ||||
this.AddTimeNotification(notification); | this.AddTimeNotification(notification); | ||||
else | else | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | for (let i = 1; i < numPlayers; ++i) | ||||
cmpPlayer.SetDisplayDiplomacyColor(data.displayDiplomacyColors); | cmpPlayer.SetDisplayDiplomacyColor(data.displayDiplomacyColors); | ||||
if (data.displayDiplomacyColors) | if (data.displayDiplomacyColors) | ||||
cmpPlayer.SetDiplomacyColor(data.displayedPlayerColors[i]); | cmpPlayer.SetDiplomacyColor(data.displayedPlayerColors[i]); | ||||
updateEntityColor(data.showAllStatusBars && (i == player || player == -1) ? | updateEntityColor(data.showAllStatusBars && (i == player || player == -1) ? | ||||
[IID_Minimap, IID_RangeOverlayRenderer, IID_RallyPointRenderer, IID_StatusBars] : | [IID_Minimap, IID_RangeOverlayRenderer, IID_RallyPointRenderer, IID_StatusBars] : | ||||
[IID_Minimap, IID_RangeOverlayRenderer, IID_RallyPointRenderer], | [IID_Minimap, IID_RangeOverlayRenderer, IID_RallyPointRenderer], | ||||
cmpRangeManager.GetEntitiesByPlayer(i)); | cmpRangeManager.GetEntitiesByPlayer(i)); | ||||
} | } | ||||
updateEntityColor([IID_Selectable, IID_StatusBars], data.selected); | updateEntityColor([IID_Selectable, IID_StatusBars], data.selected); | ||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager).UpdateColors(); | Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager).UpdateColors(); | ||||
}; | }; | ||||
GuiInterface.prototype.SetSelectionHighlight = function(player, cmd) | GuiInterface.prototype.SetSelectionHighlight = function(player, cmd) | ||||
{ | { | ||||
let playerColors = {}; // cache of owner -> color map | // Cache of owner -> color map | ||||
let playerColors = {}; | |||||
Done Inline ActionsAren't comments typically on a new line? (Also below.) Nescio: Aren't comments typically on a new line? (Also below.) | |||||
for (let ent of cmd.entities) | for (let ent of cmd.entities) | ||||
{ | { | ||||
let cmpSelectable = Engine.QueryInterface(ent, IID_Selectable); | let cmpSelectable = Engine.QueryInterface(ent, IID_Selectable); | ||||
if (!cmpSelectable) | if (!cmpSelectable) | ||||
continue; | continue; | ||||
// Find the entity's owner's color: | // Find the entity's owner's color. | ||||
let owner = INVALID_PLAYER; | let owner = INVALID_PLAYER; | ||||
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | ||||
if (cmpOwnership) | if (cmpOwnership) | ||||
owner = cmpOwnership.GetOwner(); | owner = cmpOwnership.GetOwner(); | ||||
let color = playerColors[owner]; | let color = playerColors[owner]; | ||||
if (!color) | if (!color) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | |||||
* instead of incurring a delay while PostNetworkCommand processes the set-rallypoint command (see input.js). | * instead of incurring a delay while PostNetworkCommand processes the set-rallypoint command (see input.js). | ||||
* If cmd doesn't carry a custom location, then the position to render the marker at will be read from the | * If cmd doesn't carry a custom location, then the position to render the marker at will be read from the | ||||
* RallyPoint component. | * RallyPoint component. | ||||
*/ | */ | ||||
GuiInterface.prototype.DisplayRallyPoint = function(player, cmd) | GuiInterface.prototype.DisplayRallyPoint = function(player, cmd) | ||||
{ | { | ||||
let cmpPlayer = QueryPlayerIDInterface(player); | let cmpPlayer = QueryPlayerIDInterface(player); | ||||
// If there are some rally points already displayed, first hide them | // If there are some rally points already displayed, first hide them. | ||||
for (let ent of this.entsRallyPointsDisplayed) | for (let ent of this.entsRallyPointsDisplayed) | ||||
{ | { | ||||
let cmpRallyPointRenderer = Engine.QueryInterface(ent, IID_RallyPointRenderer); | let cmpRallyPointRenderer = Engine.QueryInterface(ent, IID_RallyPointRenderer); | ||||
if (cmpRallyPointRenderer) | if (cmpRallyPointRenderer) | ||||
cmpRallyPointRenderer.SetDisplayed(false); | cmpRallyPointRenderer.SetDisplayed(false); | ||||
} | } | ||||
this.entsRallyPointsDisplayed = []; | this.entsRallyPointsDisplayed = []; | ||||
// Show the rally points for the passed entities | // Show the rally points for the passed entities. | ||||
for (let ent of cmd.entities) | for (let ent of cmd.entities) | ||||
{ | { | ||||
let cmpRallyPointRenderer = Engine.QueryInterface(ent, IID_RallyPointRenderer); | let cmpRallyPointRenderer = Engine.QueryInterface(ent, IID_RallyPointRenderer); | ||||
if (!cmpRallyPointRenderer) | if (!cmpRallyPointRenderer) | ||||
continue; | continue; | ||||
// entity must have a rally point component to display a rally point marker | // Entity must have a rally point component to display a rally point marker | ||||
// (regardless of whether cmd specifies a custom location) | // (regardless of whether cmd specifies a custom location). | ||||
let cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint); | let cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint); | ||||
if (!cmpRallyPoint) | if (!cmpRallyPoint) | ||||
continue; | continue; | ||||
// Verify the owner | // Verify the owner. | ||||
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | ||||
if (!(cmpPlayer && cmpPlayer.CanControlAllUnits())) | if (!(cmpPlayer && cmpPlayer.CanControlAllUnits())) | ||||
if (!cmpOwnership || cmpOwnership.GetOwner() != player) | if (!cmpOwnership || cmpOwnership.GetOwner() != player) | ||||
continue; | continue; | ||||
// If the command was passed an explicit position, use that and | // If the command was passed an explicit position, use that and | ||||
// override the real rally point position; otherwise use the real position | // override the real rally point position; otherwise use the real position. | ||||
let pos; | let pos; | ||||
if (cmd.x && cmd.z) | if (cmd.x && cmd.z) | ||||
pos = cmd; | pos = cmd; | ||||
else | else | ||||
pos = cmpRallyPoint.GetPositions()[0]; // may return undefined if no rally point is set | { | ||||
// May return undefined if no rally point is set. | |||||
pos = cmpRallyPoint.GetPositions()[0]; | |||||
} | |||||
if (pos) | if (pos) | ||||
{ | { | ||||
// Only update the position if we changed it (cmd.queued is set) | // Only update the position if we changed it (cmd.queued is set). | ||||
if ("queued" in cmd) | if ("queued" in cmd) | ||||
if (cmd.queued == true) | if (cmd.queued == true) | ||||
cmpRallyPointRenderer.AddPosition({ 'x': pos.x, 'y': pos.z }); // AddPosition takes a CFixedVector2D which has X/Y components, not X/Z | { | ||||
SilierUnsubmitted Done Inline ActionsWhy brackets for one line ? Silier: Why brackets for one line ?
see similar solution at L1427 | |||||
// AddPosition takes a CFixedVector2D which has X/Y components, not X/Z. | |||||
cmpRallyPointRenderer.AddPosition({ 'x': pos.x, 'y': pos.z }); | |||||
elexisUnsubmitted Done Inline Actions(Objects storing positions should be use the Vector prototype, so that one can use these algebraic operations. If it's globally consistent then these operations are available by default and new code would also be introduced with that feature.) elexis: (Objects storing positions should be use the Vector prototype, so that one can use these… | |||||
StanUnsubmitted Done Inline ActionsIs it still worth creating new objects? I still like having vectors though. Wonder if we couldn't just pass pos to cpp Stan: Is it still worth creating new objects? I still like having vectors though.
Wonder if we… | |||||
FreagarachAuthorUnsubmitted Done Inline Actions"// Note that Add-/SetPosition take a CFixedVector2D which has X/Y components, not X/Z." Freagarach: "// Note that Add-/SetPosition take a CFixedVector2D which has X/Y components, not X/Z." | |||||
} | |||||
else | else | ||||
cmpRallyPointRenderer.SetPosition({ 'x': pos.x, 'y': pos.z }); // SetPosition takes a CFixedVector2D which has X/Y components, not X/Z | { | ||||
// SetPosition takes a CFixedVector2D which has X/Y components, not X/Z. | |||||
cmpRallyPointRenderer.SetPosition({ 'x': pos.x, 'y': pos.z }); | |||||
} | |||||
// rebuild the renderer when not set (when reading saved game or in case of building update) | // Rebuild the renderer when not set (when reading saved game or in case of building update). | ||||
else if (!cmpRallyPointRenderer.IsSet()) | else if (!cmpRallyPointRenderer.IsSet()) | ||||
for (let posi of cmpRallyPoint.GetPositions()) | for (let posi of cmpRallyPoint.GetPositions()) | ||||
cmpRallyPointRenderer.AddPosition({ 'x': posi.x, 'y': posi.z }); | cmpRallyPointRenderer.AddPosition({ 'x': posi.x, 'y': posi.z }); | ||||
cmpRallyPointRenderer.SetDisplayed(true); | cmpRallyPointRenderer.SetDisplayed(true); | ||||
// remember which entities have their rally points displayed so we can hide them again | // Remember which entities have their rally points displayed so we can hide them again. | ||||
this.entsRallyPointsDisplayed.push(ent); | this.entsRallyPointsDisplayed.push(ent); | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
GuiInterface.prototype.AddTargetMarker = function(player, cmd) | GuiInterface.prototype.AddTargetMarker = function(player, cmd) | ||||
{ | { | ||||
let ent = Engine.AddLocalEntity(cmd.template); | let ent = Engine.AddLocalEntity(cmd.template); | ||||
Show All 25 Lines | GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd) | ||||
let result = { | let result = { | ||||
"success": false, | "success": false, | ||||
"message": "", | "message": "", | ||||
"parameters": {}, | "parameters": {}, | ||||
"translateMessage": false, | "translateMessage": false, | ||||
"translateParameters": [], | "translateParameters": [], | ||||
}; | }; | ||||
// See if we're changing template | // See if we're changing template. | ||||
SilierUnsubmitted Done Inline ActionsI think this one can be nuked Silier: I think this one can be nuked
same for L1019 L1023 | |||||
if (!this.placementEntity || this.placementEntity[0] != cmd.template) | if (!this.placementEntity || this.placementEntity[0] != cmd.template) | ||||
{ | { | ||||
// Destroy the old preview if there was one | // Destroy the old preview if there was one. | ||||
if (this.placementEntity) | if (this.placementEntity) | ||||
Engine.DestroyEntity(this.placementEntity[1]); | Engine.DestroyEntity(this.placementEntity[1]); | ||||
// Load the new template | // Load the new template. | ||||
if (cmd.template == "") | if (cmd.template == "") | ||||
this.placementEntity = undefined; | this.placementEntity = undefined; | ||||
else | else | ||||
this.placementEntity = [cmd.template, Engine.AddLocalEntity("preview|" + cmd.template)]; | this.placementEntity = [cmd.template, Engine.AddLocalEntity("preview|" + cmd.template)]; | ||||
} | } | ||||
if (this.placementEntity) | if (this.placementEntity) | ||||
{ | { | ||||
let ent = this.placementEntity[1]; | let ent = this.placementEntity[1]; | ||||
// Move the preview into the right location | // Move the preview into the right location. | ||||
let pos = Engine.QueryInterface(ent, IID_Position); | let pos = Engine.QueryInterface(ent, IID_Position); | ||||
if (pos) | if (pos) | ||||
{ | { | ||||
pos.JumpTo(cmd.x, cmd.z); | pos.JumpTo(cmd.x, cmd.z); | ||||
pos.SetYRotation(cmd.angle); | pos.SetYRotation(cmd.angle); | ||||
} | } | ||||
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | ||||
cmpOwnership.SetOwner(player); | cmpOwnership.SetOwner(player); | ||||
// Check whether building placement is valid | // Check whether building placement is valid. | ||||
let cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); | let cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); | ||||
if (!cmpBuildRestrictions) | if (!cmpBuildRestrictions) | ||||
error("cmpBuildRestrictions not defined"); | error("cmpBuildRestrictions not defined"); | ||||
else | else | ||||
result = cmpBuildRestrictions.CheckPlacement(); | result = cmpBuildRestrictions.CheckPlacement(); | ||||
let cmpRangeOverlayManager = Engine.QueryInterface(ent, IID_RangeOverlayManager); | let cmpRangeOverlayManager = Engine.QueryInterface(ent, IID_RangeOverlayManager); | ||||
if (cmpRangeOverlayManager) | if (cmpRangeOverlayManager) | ||||
cmpRangeOverlayManager.SetEnabled(true, this.enabledVisualRangeOverlayTypes); | cmpRangeOverlayManager.SetEnabled(true, this.enabledVisualRangeOverlayTypes); | ||||
// Set it to a red shade if this is an invalid location | // Set it to a red shade if this is an invalid location. | ||||
let cmpVisual = Engine.QueryInterface(ent, IID_Visual); | let cmpVisual = Engine.QueryInterface(ent, IID_Visual); | ||||
if (cmpVisual) | if (cmpVisual) | ||||
{ | { | ||||
if (cmd.actorSeed !== undefined) | if (cmd.actorSeed !== undefined) | ||||
cmpVisual.SetActorSeed(cmd.actorSeed); | cmpVisual.SetActorSeed(cmd.actorSeed); | ||||
if (!result.success) | if (!result.success) | ||||
cmpVisual.SetShadingColor(1.4, 0.4, 0.4, 1); | cmpVisual.SetShadingColor(1.4, 0.4, 0.4, 1); | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
* of picking a starting point), and that therefore only the first entity in the wall (a tower) should be | * of picking a starting point), and that therefore only the first entity in the wall (a tower) should be | ||||
* previewed. | * previewed. | ||||
* @param cmd.snapEntities List of candidate entities to snap the start and ending positions to. | * @param cmd.snapEntities List of candidate entities to snap the start and ending positions to. | ||||
*/ | */ | ||||
GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd) | GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd) | ||||
{ | { | ||||
let wallSet = cmd.wallSet; | let wallSet = cmd.wallSet; | ||||
// Did the start position snap to anything? | |||||
// If we snapped, was it to an entity? If yes, hold that entity's ID. | |||||
let start = { | let start = { | ||||
"pos": cmd.start, | "pos": cmd.start, | ||||
"angle": 0, | "angle": 0, | ||||
"snapped": false, // did the start position snap to anything? | "snapped": false, | ||||
"snappedEnt": INVALID_ENTITY, // if we snapped, was it to an entity? if yes, holds that entity's ID | "snappedEnt": INVALID_ENTITY, | ||||
Done Inline Actionshold Nescio: hold | |||||
Done Inline ActionsWhat they meant here was probably something like: "If yes, this holds (...)". I'm not even sure these comments (and below) are needed, because it seems obvious from the code, but that's not up to me ;) Freagarach: What they meant here was probably something like: "If yes, this holds (...)". I'm not even sure… | |||||
}; | }; | ||||
// Did the end position snap to anything? | |||||
// If we snapped, was it to an entity? If yes, hold that entity's ID. | |||||
Done Inline ActionsI still managed to forget this. Freagarach: I still managed to forget this. | |||||
let end = { | let end = { | ||||
"pos": cmd.end, | "pos": cmd.end, | ||||
"angle": 0, | "angle": 0, | ||||
"snapped": false, // did the start position snap to anything? | "snapped": false, | ||||
"snappedEnt": INVALID_ENTITY, // if we snapped, was it to an entity? if yes, holds that entity's ID | "snappedEnt": INVALID_ENTITY, | ||||
Done Inline Actionsidem Nescio: idem | |||||
}; | }; | ||||
// -------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------- | ||||
// do some entity cache management and check for snapping | // Do some entity cache management and check for snapping. | ||||
if (!this.placementWallEntities) | if (!this.placementWallEntities) | ||||
this.placementWallEntities = {}; | this.placementWallEntities = {}; | ||||
if (!wallSet) | if (!wallSet) | ||||
{ | { | ||||
// we're clearing the preview, clear the entity cache and bail | // We're clearing the preview, clear the entity cache and bail. | ||||
for (let tpl in this.placementWallEntities) | for (let tpl in this.placementWallEntities) | ||||
{ | { | ||||
for (let ent of this.placementWallEntities[tpl].entities) | for (let ent of this.placementWallEntities[tpl].entities) | ||||
Engine.DestroyEntity(ent); | Engine.DestroyEntity(ent); | ||||
this.placementWallEntities[tpl].numUsed = 0; | this.placementWallEntities[tpl].numUsed = 0; | ||||
this.placementWallEntities[tpl].entities = []; | this.placementWallEntities[tpl].entities = []; | ||||
// keep template data around | // Keep template data around. | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
// Move all existing cached entities outside of the world and reset their use count | // Move all existing cached entities outside of the world and reset their use count. | ||||
SilierUnsubmitted Done Inline ActionsThis should be obvious from next lines Silier: This should be obvious from next lines | |||||
for (let tpl in this.placementWallEntities) | for (let tpl in this.placementWallEntities) | ||||
{ | { | ||||
for (let ent of this.placementWallEntities[tpl].entities) | for (let ent of this.placementWallEntities[tpl].entities) | ||||
{ | { | ||||
let pos = Engine.QueryInterface(ent, IID_Position); | let pos = Engine.QueryInterface(ent, IID_Position); | ||||
if (pos) | if (pos) | ||||
pos.MoveOutOfWorld(); | pos.MoveOutOfWorld(); | ||||
} | } | ||||
this.placementWallEntities[tpl].numUsed = 0; | this.placementWallEntities[tpl].numUsed = 0; | ||||
} | } | ||||
// Create cache entries for templates we haven't seen before | // Create cache entries for templates we haven't seen before. | ||||
for (let type in wallSet.templates) | for (let type in wallSet.templates) | ||||
{ | { | ||||
if (type == "curves") | if (type == "curves") | ||||
continue; | continue; | ||||
let tpl = wallSet.templates[type]; | let tpl = wallSet.templates[type]; | ||||
if (!(tpl in this.placementWallEntities)) | if (!(tpl in this.placementWallEntities)) | ||||
{ | { | ||||
this.placementWallEntities[tpl] = { | this.placementWallEntities[tpl] = { | ||||
"numUsed": 0, | "numUsed": 0, | ||||
"entities": [], | "entities": [], | ||||
"templateData": this.GetTemplateData(player, tpl), | "templateData": this.GetTemplateData(player, tpl), | ||||
}; | }; | ||||
// ensure that the loaded template data contains a wallPiece component | // Ensure that the loaded template data contains a wallPiece component. | ||||
if (!this.placementWallEntities[tpl].templateData.wallPiece) | if (!this.placementWallEntities[tpl].templateData.wallPiece) | ||||
{ | { | ||||
error("[SetWallPlacementPreview] No WallPiece component found for wall set template '" + tpl + "'"); | error("[SetWallPlacementPreview] No WallPiece component found for wall set template '" + tpl + "'"); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// prevent division by zero errors further on if the start and end positions are the same | // Prevent division by zero errors further on if the start and end positions are the same. | ||||
if (end.pos && (start.pos.x === end.pos.x && start.pos.z === end.pos.z)) | if (end.pos && (start.pos.x === end.pos.x && start.pos.z === end.pos.z)) | ||||
end.pos = undefined; | end.pos = undefined; | ||||
// See if we need to snap the start and/or end coordinates to any of our list of snap entities. Note that, despite the list | // See if we need to snap the start and/or end coordinates to any of our list of snap entities. Note that, despite the list | ||||
// of snapping candidate entities, it might still snap to e.g. terrain features. Use the "ent" key in the returned snapping | // of snapping candidate entities, it might still snap to e.g. terrain features. Use the "ent" key in the returned snapping | ||||
// data to determine whether it snapped to an entity (if any), and to which one (see GetFoundationSnapData). | // data to determine whether it snapped to an entity (if any), and to which one (see GetFoundationSnapData). | ||||
if (cmd.snapEntities) | if (cmd.snapEntities) | ||||
{ | { | ||||
let snapRadius = this.placementWallEntities[wallSet.templates.tower].templateData.wallPiece.length * 0.5; // determined through trial and error | // Magic value of 0.5 (below) was determined through trial and error. | ||||
PolakrityUnsubmitted Done Inline ActionsThis calculation seems to get the radius so 0.5 is not really a magic value, no? Polakrity: This calculation seems to get the radius so 0.5 is not really a magic value, no?
It would be… | |||||
FreagarachAuthorUnsubmitted Done Inline ActionsYes, but according to the former comment it was determined through trail and error, so that would imply it is not really purposfully dividing by 2. Freagarach: Yes, but according to the former comment it was determined through trail and error, so that… | |||||
StanUnsubmitted Done Inline ActionsThree patches modifying that line (this one, sockets, restoring turrets) Stan: Three patches modifying that line (this one, sockets, restoring turrets) | |||||
let snapRadius = this.placementWallEntities[wallSet.templates.tower].templateData.wallPiece.length * 0.5; | |||||
let startSnapData = this.GetFoundationSnapData(player, { | let startSnapData = this.GetFoundationSnapData(player, { | ||||
"x": start.pos.x, | "x": start.pos.x, | ||||
"z": start.pos.z, | "z": start.pos.z, | ||||
"template": wallSet.templates.tower, | "template": wallSet.templates.tower, | ||||
"snapEntities": cmd.snapEntities, | "snapEntities": cmd.snapEntities, | ||||
"snapRadius": snapRadius, | "snapRadius": snapRadius, | ||||
}); | }); | ||||
Show All 26 Lines | if (end.pos) | ||||
end.snapped = true; | end.snapped = true; | ||||
if (endSnapData.ent) | if (endSnapData.ent) | ||||
end.snappedEnt = endSnapData.ent; | end.snappedEnt = endSnapData.ent; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// clear the single-building preview entity (we'll be rolling our own) | // Clear the single-building preview entity (we'll be rolling our own). | ||||
this.SetBuildingPlacementPreview(player, { "template": "" }); | this.SetBuildingPlacementPreview(player, { "template": "" }); | ||||
// -------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------- | ||||
// calculate wall placement and position preview entities | // Calculate wall placement and position preview entities. | ||||
let result = { | let result = { | ||||
"pieces": [], | "pieces": [], | ||||
"cost": { "population": 0, "populationBonus": 0, "time": 0 }, | "cost": { "population": 0, "populationBonus": 0, "time": 0 }, | ||||
}; | }; | ||||
for (let res of Resources.GetCodes()) | for (let res of Resources.GetCodes()) | ||||
result.cost[res] = 0; | result.cost[res] = 0; | ||||
Show All 17 Lines | GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd) | ||||
// Additionally, in the situation that we're snapping to merely a foundation of a tower instead of a fully | // Additionally, in the situation that we're snapping to merely a foundation of a tower instead of a fully | ||||
// constructed one, we'll need an extra preview entity for the starting tower, which also must not be obstructed | // constructed one, we'll need an extra preview entity for the starting tower, which also must not be obstructed | ||||
// by the foundation it snaps to. | // by the foundation it snaps to. | ||||
if (start.snappedEnt && start.snappedEnt != INVALID_ENTITY) | if (start.snappedEnt && start.snappedEnt != INVALID_ENTITY) | ||||
{ | { | ||||
let startEntObstruction = Engine.QueryInterface(start.snappedEnt, IID_Obstruction); | let startEntObstruction = Engine.QueryInterface(start.snappedEnt, IID_Obstruction); | ||||
if (previewEntities.length > 0 && startEntObstruction) | if (previewEntities.length > 0 && startEntObstruction) | ||||
SilierUnsubmitted Done Inline Actionscould you change to previewEntites.length && Silier: could you change to `previewEntites.length &&` | |||||
previewEntities[0].controlGroups = [startEntObstruction.GetControlGroup()]; | previewEntities[0].controlGroups = [startEntObstruction.GetControlGroup()]; | ||||
// if we're snapping to merely a foundation, add an extra preview tower and also set it to the same control group | // If we're snapping to merely a foundation, add an extra preview tower and also set it to the same control group. | ||||
let startEntState = this.GetEntityState(player, start.snappedEnt); | let startEntState = this.GetEntityState(player, start.snappedEnt); | ||||
if (startEntState.foundation) | if (startEntState.foundation) | ||||
{ | { | ||||
let cmpPosition = Engine.QueryInterface(start.snappedEnt, IID_Position); | let cmpPosition = Engine.QueryInterface(start.snappedEnt, IID_Position); | ||||
if (cmpPosition) | if (cmpPosition) | ||||
previewEntities.unshift({ | previewEntities.unshift({ | ||||
"template": wallSet.templates.tower, | "template": wallSet.templates.tower, | ||||
"pos": start.pos, | "pos": start.pos, | ||||
"angle": cmpPosition.GetRotation().y, | "angle": cmpPosition.GetRotation().y, | ||||
"controlGroups": [startEntObstruction ? startEntObstruction.GetControlGroup() : undefined], | "controlGroups": [startEntObstruction ? startEntObstruction.GetControlGroup() : undefined], | ||||
"excludeFromResult": true, // preview only, must not appear in the result | "excludeFromResult": true, // Preview only, must not appear in the result. | ||||
}); | }); | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Didn't snap to an existing entity, add the starting tower manually. To prevent odd-looking rotation jumps | // Didn't snap to an existing entity, add the starting tower manually. To prevent odd-looking rotation jumps | ||||
// when shift-clicking to build a wall, reuse the placement angle that was last seen on a validly positioned | // when shift-clicking to build a wall, reuse the placement angle that was last seen on a validly positioned | ||||
// wall piece. | // wall piece. | ||||
Show All 13 Lines | previewEntities.unshift({ | ||||
"template": wallSet.templates.tower, | "template": wallSet.templates.tower, | ||||
"pos": start.pos, | "pos": start.pos, | ||||
"angle": previewEntities.length > 0 ? previewEntities[0].angle : this.placementWallLastAngle | "angle": previewEntities.length > 0 ? previewEntities[0].angle : this.placementWallLastAngle | ||||
}); | }); | ||||
} | } | ||||
if (end.pos) | if (end.pos) | ||||
{ | { | ||||
// Analogous to the starting side case above | // Analogous to the starting side case above. | ||||
if (end.snappedEnt && end.snappedEnt != INVALID_ENTITY) | if (end.snappedEnt && end.snappedEnt != INVALID_ENTITY) | ||||
{ | { | ||||
let endEntObstruction = Engine.QueryInterface(end.snappedEnt, IID_Obstruction); | let endEntObstruction = Engine.QueryInterface(end.snappedEnt, IID_Obstruction); | ||||
// Note that it's possible for the last entity in previewEntities to be the same as the first, i.e. the | // Note that it's possible for the last entity in previewEntities to be the same as the first, i.e. the | ||||
// same wall piece snapping to both a starting and an ending tower. And it might be more common than you would | // same wall piece snapping to both a starting and an ending tower. And it might be more common than you would | ||||
// expect; the allowed overlap between wall segments and towers facilitates this to some degree. To deal with | // expect; the allowed overlap between wall segments and towers facilitates this to some degree. To deal with | ||||
// the possibility of dual initial control groups, we use a '.controlGroups' array rather than a single | // the possibility of dual initial control groups, we use a '.controlGroups' array rather than a single | ||||
// '.controlGroup' property. Note that this array can only ever have 0, 1 or 2 elements (checked at a later time). | // '.controlGroup' property. Note that this array can only ever have 0, 1 or 2 elements (checked at a later time). | ||||
if (previewEntities.length > 0 && endEntObstruction) | if (previewEntities.length > 0 && endEntObstruction) | ||||
{ | { | ||||
previewEntities[previewEntities.length-1].controlGroups = previewEntities[previewEntities.length-1].controlGroups || []; | previewEntities[previewEntities.length-1].controlGroups = previewEntities[previewEntities.length-1].controlGroups || []; | ||||
previewEntities[previewEntities.length-1].controlGroups.push(endEntObstruction.GetControlGroup()); | previewEntities[previewEntities.length-1].controlGroups.push(endEntObstruction.GetControlGroup()); | ||||
} | } | ||||
// if we're snapping to a foundation, add an extra preview tower and also set it to the same control group | // If we're snapping to a foundation, add an extra preview tower and also set it to the same control group. | ||||
let endEntState = this.GetEntityState(player, end.snappedEnt); | let endEntState = this.GetEntityState(player, end.snappedEnt); | ||||
if (endEntState.foundation) | if (endEntState.foundation) | ||||
{ | { | ||||
let cmpPosition = Engine.QueryInterface(end.snappedEnt, IID_Position); | let cmpPosition = Engine.QueryInterface(end.snappedEnt, IID_Position); | ||||
if (cmpPosition) | if (cmpPosition) | ||||
previewEntities.push({ | previewEntities.push({ | ||||
"template": wallSet.templates.tower, | "template": wallSet.templates.tower, | ||||
"pos": end.pos, | "pos": end.pos, | ||||
"angle": cmpPosition.GetRotation().y, | "angle": cmpPosition.GetRotation().y, | ||||
"controlGroups": [endEntObstruction ? endEntObstruction.GetControlGroup() : undefined], | "controlGroups": [endEntObstruction ? endEntObstruction.GetControlGroup() : undefined], | ||||
FreagarachAuthorUnsubmitted Done Inline Actions[undefined].length == 1 I wonder whether that was intended. (From rP11760.) Freagarach: `[undefined].length == 1` I wonder whether that was intended. (From rP11760.) | |||||
"excludeFromResult": true | "excludeFromResult": true | ||||
}); | }); | ||||
} | } | ||||
} | |||||
SilierUnsubmitted Done Inline Actionsyou moved this, bring it back, you have changed logic Silier: you moved this, bring it back, you have changed logic | |||||
else | else | ||||
previewEntities.push({ | previewEntities.push({ | ||||
"template": wallSet.templates.tower, | "template": wallSet.templates.tower, | ||||
"pos": end.pos, | "pos": end.pos, | ||||
"angle": previewEntities.length > 0 ? previewEntities[previewEntities.length-1].angle : this.placementWallLastAngle | "angle": previewEntities.length > 0 ? previewEntities[previewEntities.length-1].angle : this.placementWallLastAngle | ||||
}); | }); | ||||
} | } | ||||
} | |||||
let cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); | let cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); | ||||
if (!cmpTerrain) | if (!cmpTerrain) | ||||
{ | { | ||||
error("[SetWallPlacementPreview] System Terrain component not found"); | error("[SetWallPlacementPreview] System Terrain component not found"); | ||||
return false; | return false; | ||||
} | } | ||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
if (!cmpRangeManager) | if (!cmpRangeManager) | ||||
{ | { | ||||
error("[SetWallPlacementPreview] System RangeManager component not found"); | error("[SetWallPlacementPreview] System RangeManager component not found"); | ||||
return false; | return false; | ||||
} | } | ||||
// Loop through the preview entities, and construct the subset of them that need to be, and can be, validly constructed | // Loop through the preview entities, and construct the subset of them that need to be, and can be, validly constructed | ||||
// to build at least a part of the wall (meaning that the subset is truncated after the first entity that needs to be, | // to build at least a part of the wall (meaning that the subset is truncated after the first entity that needs to be, | ||||
// but cannot validly be, constructed). See method-level documentation for more details. | // but cannot validly be, constructed). See method-level documentation for more details. | ||||
let allPiecesValid = true; | let allPiecesValid = true; | ||||
let numRequiredPieces = 0; // number of entities that are required to build the entire wall, regardless of validity | // Number of entities that are required to build the entire wall, regardless of validity. | ||||
let numRequiredPieces = 0; | |||||
for (let i = 0; i < previewEntities.length; ++i) | for (let i = 0; i < previewEntities.length; ++i) | ||||
{ | { | ||||
let entInfo = previewEntities[i]; | let entInfo = previewEntities[i]; | ||||
let ent = null; | let ent = null; | ||||
let tpl = entInfo.template; | let tpl = entInfo.template; | ||||
let tplData = this.placementWallEntities[tpl].templateData; | let tplData = this.placementWallEntities[tpl].templateData; | ||||
let entPool = this.placementWallEntities[tpl]; | let entPool = this.placementWallEntities[tpl]; | ||||
if (entPool.numUsed >= entPool.entities.length) | if (entPool.numUsed >= entPool.entities.length) | ||||
{ | { | ||||
// allocate new entity | // Allocate new entity. | ||||
SilierUnsubmitted Done Inline ActionsThis looks not needed same L1427 Silier: This looks not needed same L1427 | |||||
ent = Engine.AddLocalEntity("preview|" + tpl); | ent = Engine.AddLocalEntity("preview|" + tpl); | ||||
entPool.entities.push(ent); | entPool.entities.push(ent); | ||||
} | } | ||||
else | else | ||||
// reuse an existing one | // Reuse an existing one. | ||||
ent = entPool.entities[entPool.numUsed]; | ent = entPool.entities[entPool.numUsed]; | ||||
if (!ent) | if (!ent) | ||||
{ | { | ||||
error("[SetWallPlacementPreview] Failed to allocate or reuse preview entity of template '" + tpl + "'"); | error("[SetWallPlacementPreview] Failed to allocate or reuse preview entity of template '" + tpl + "'"); | ||||
continue; | continue; | ||||
} | } | ||||
// move piece to right location | // Move piece to right location. | ||||
// TODO: consider reusing SetBuildingPlacementReview for this, enhanced to be able to deal with multiple entities | // TODO: Consider reusing SetBuildingPlacementReview for this, enhanced to be able to deal with multiple entities. | ||||
let cmpPosition = Engine.QueryInterface(ent, IID_Position); | let cmpPosition = Engine.QueryInterface(ent, IID_Position); | ||||
if (cmpPosition) | if (cmpPosition) | ||||
{ | { | ||||
cmpPosition.JumpTo(entInfo.pos.x, entInfo.pos.z); | cmpPosition.JumpTo(entInfo.pos.x, entInfo.pos.z); | ||||
cmpPosition.SetYRotation(entInfo.angle); | cmpPosition.SetYRotation(entInfo.angle); | ||||
// if this piece is a tower, then it should have a Y position that is at least as high as its surrounding pieces | // If this piece is a tower, then it should have a Y position that is at least as high as its surrounding pieces. | ||||
if (tpl === wallSet.templates.tower) | if (tpl === wallSet.templates.tower) | ||||
{ | { | ||||
let terrainGroundPrev = null; | let terrainGroundPrev = null; | ||||
let terrainGroundNext = null; | let terrainGroundNext = null; | ||||
if (i > 0) | if (i > 0) | ||||
terrainGroundPrev = cmpTerrain.GetGroundLevel(previewEntities[i-1].pos.x, previewEntities[i-1].pos.z); | terrainGroundPrev = cmpTerrain.GetGroundLevel(previewEntities[i-1].pos.x, previewEntities[i-1].pos.z); | ||||
Show All 39 Lines | if (entInfo.controlGroups && entInfo.controlGroups.length > 0) | ||||
primaryControlGroup = entInfo.controlGroups[0]; | primaryControlGroup = entInfo.controlGroups[0]; | ||||
if (entInfo.controlGroups.length > 1) | if (entInfo.controlGroups.length > 1) | ||||
secondaryControlGroup = entInfo.controlGroups[1]; | secondaryControlGroup = entInfo.controlGroups[1]; | ||||
} | } | ||||
cmpObstruction.SetControlGroup(primaryControlGroup); | cmpObstruction.SetControlGroup(primaryControlGroup); | ||||
cmpObstruction.SetControlGroup2(secondaryControlGroup); | cmpObstruction.SetControlGroup2(secondaryControlGroup); | ||||
// check whether this wall piece can be validly positioned here | // Check whether this wall piece can be validly positioned here. | ||||
elexisUnsubmitted Done Inline Actions(A bit noisy) elexis: (A bit noisy) | |||||
let validPlacement = false; | let validPlacement = false; | ||||
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); | ||||
cmpOwnership.SetOwner(player); | cmpOwnership.SetOwner(player); | ||||
// Check whether it's in a visible or fogged region | // Check whether it's in a visible or fogged region. | ||||
// TODO: should definitely reuse SetBuildingPlacementPreview, this is just straight up copy/pasta | // TODO: Should definitely reuse SetBuildingPlacementPreview, this is just straight up copy/pasta. | ||||
let visible = cmpRangeManager.GetLosVisibility(ent, player) != "hidden"; | let visible = cmpRangeManager.GetLosVisibility(ent, player) != "hidden"; | ||||
if (visible) | if (visible) | ||||
{ | { | ||||
let cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); | let cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions); | ||||
if (!cmpBuildRestrictions) | if (!cmpBuildRestrictions) | ||||
{ | { | ||||
error("[SetWallPlacementPreview] cmpBuildRestrictions not defined for preview entity of template '" + tpl + "'"); | error("[SetWallPlacementPreview] cmpBuildRestrictions not defined for preview entity of template '" + tpl + "'"); | ||||
continue; | continue; | ||||
} | } | ||||
// TODO: Handle results of CheckPlacement | // TODO: Handle results of CheckPlacement. | ||||
validPlacement = cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success; | validPlacement = cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success; | ||||
// If a wall piece has two control groups, it's likely a segment that spans | // If a wall piece has two control groups, it's likely a segment that spans | ||||
// between two existing towers. To avoid placing a duplicate wall segment, | // between two existing towers. To avoid placing a duplicate wall segment, | ||||
// check for collisions with entities that share both control groups. | // check for collisions with entities that share both control groups. | ||||
if (validPlacement && entInfo.controlGroups && entInfo.controlGroups.length > 1) | if (validPlacement && entInfo.controlGroups && entInfo.controlGroups.length > 1) | ||||
validPlacement = cmpObstruction.CheckDuplicateFoundation(); | validPlacement = cmpObstruction.CheckDuplicateFoundation(); | ||||
} | } | ||||
Show All 16 Lines | if (allPiecesValid && !entInfo.excludeFromResult) | ||||
result.pieces.push({ | result.pieces.push({ | ||||
"template": tpl, | "template": tpl, | ||||
"x": entInfo.pos.x, | "x": entInfo.pos.x, | ||||
"z": entInfo.pos.z, | "z": entInfo.pos.z, | ||||
"angle": entInfo.angle, | "angle": entInfo.angle, | ||||
}); | }); | ||||
this.placementWallLastAngle = entInfo.angle; | this.placementWallLastAngle = entInfo.angle; | ||||
// grab the cost of this wall piece and add it up (note; preview entities don't have their Cost components | // Grab the cost of this wall piece and add it up (note; preview entities don't have their Cost components | ||||
// copied over, so we need to fetch it from the template instead). | // copied over, so we need to fetch it from the template instead). | ||||
// TODO: we should really use a Cost object or at least some utility functions for this, this is mindless | // TODO: We should really use a Cost object or at least some utility functions for this, this is mindless | ||||
// boilerplate that's probably duplicated in tons of places. | // boilerplate that's probably duplicated in tons of places. | ||||
for (let res of Resources.GetCodes().concat(["population", "populationBonus", "time"])) | for (let res of Resources.GetCodes().concat(["population", "populationBonus", "time"])) | ||||
result.cost[res] += tplData.cost[res]; | result.cost[res] += tplData.cost[res]; | ||||
} | } | ||||
let canAfford = true; | let canAfford = true; | ||||
let cmpPlayer = QueryPlayerIDInterface(player, IID_Player); | let cmpPlayer = QueryPlayerIDInterface(player, IID_Player); | ||||
if (cmpPlayer && cmpPlayer.GetNeededResources(result.cost)) | if (cmpPlayer && cmpPlayer.GetNeededResources(result.cost)) | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | GuiInterface.prototype.GetFoundationSnapData = function(player, data) | ||||
if (!template) | if (!template) | ||||
{ | { | ||||
warn("[GetFoundationSnapData] Failed to load template '" + data.template + "'"); | warn("[GetFoundationSnapData] Failed to load template '" + data.template + "'"); | ||||
return false; | return false; | ||||
} | } | ||||
if (data.snapEntities && data.snapRadius && data.snapRadius > 0) | if (data.snapEntities && data.snapRadius && data.snapRadius > 0) | ||||
{ | { | ||||
// see if {data.x, data.z} is inside the snap radius of any of the snap entities; and if so, to which it is closest | // See if {data.x, data.z} is inside the snap radius of any of the snap entities; and if so, to which it is closest. | ||||
// (TODO: break unlikely ties by choosing the lowest entity ID) | // (TODO: Break unlikely ties by choosing the lowest entity ID.) | ||||
let minDist2 = -1; | let minDist2 = -1; | ||||
let minDistEntitySnapData = null; | let minDistEntitySnapData = null; | ||||
let radius2 = data.snapRadius * data.snapRadius; | let radius2 = data.snapRadius * data.snapRadius; | ||||
for (let ent of data.snapEntities) | for (let ent of data.snapEntities) | ||||
{ | { | ||||
let cmpPosition = Engine.QueryInterface(ent, IID_Position); | let cmpPosition = Engine.QueryInterface(ent, IID_Position); | ||||
if (!cmpPosition || !cmpPosition.IsInWorld()) | if (!cmpPosition || !cmpPosition.IsInWorld()) | ||||
continue; | continue; | ||||
let pos = cmpPosition.GetPosition(); | let pos = cmpPosition.GetPosition(); | ||||
let dist2 = (data.x - pos.x) * (data.x - pos.x) + (data.z - pos.z) * (data.z - pos.z); | let dist2 = (data.x - pos.x) * (data.x - pos.x) + (data.z - pos.z) * (data.z - pos.z); | ||||
if (dist2 > radius2) | if (dist2 > radius2) | ||||
continue; | continue; | ||||
if (minDist2 < 0 || dist2 < minDist2) | if (minDist2 < 0 || dist2 < minDist2) | ||||
{ | { | ||||
minDist2 = dist2; | minDist2 = dist2; | ||||
minDistEntitySnapData = { | minDistEntitySnapData = { | ||||
"x": pos.x, | "x": pos.x, | ||||
"z": pos.z, | "z": pos.z, | ||||
"angle": cmpPosition.GetRotation().y, | "angle": cmpPosition.GetRotation().y, | ||||
"ent": ent | "ent": ent | ||||
SilierUnsubmitted Done Inline Actionsthis should end with , Silier: this should end with `,` | |||||
}; | }; | ||||
} | } | ||||
} | } | ||||
if (minDistEntitySnapData != null) | if (minDistEntitySnapData != null) | ||||
return minDistEntitySnapData; | return minDistEntitySnapData; | ||||
} | } | ||||
Show All 39 Lines | GuiInterface.prototype.FindIdleUnits = function(player, data) | ||||
for (let entity of cmpRangeManager.GetEntitiesByPlayer(player)) | for (let entity of cmpRangeManager.GetEntitiesByPlayer(player)) | ||||
{ | { | ||||
let filtered = this.IdleUnitFilter(entity, data.idleClasses, data.excludeUnits); | let filtered = this.IdleUnitFilter(entity, data.idleClasses, data.excludeUnits); | ||||
if (!filtered.idle) | if (!filtered.idle) | ||||
continue; | continue; | ||||
// If the entity is in the 'current' (first, 0) bucket on a resumed search, it must be after the "previous" unit, if any. | // If the entity is in the 'current' (first, 0) bucket on a resumed search, it must be after the "previous" unit, if any. | ||||
// By adding to the 'end', there is no pause if the series of units loops. | // By adding to the 'end', there is no pause if the series of units loops. | ||||
var bucket = filtered.bucket; | let bucket = filtered.bucket; | ||||
if(bucket == 0 && data.prevUnit && entity <= data.prevUnit) | if(bucket == 0 && data.prevUnit && entity <= data.prevUnit) | ||||
bucket = data.idleClasses.length; | bucket = data.idleClasses.length; | ||||
if (!idleUnits[bucket]) | if (!idleUnits[bucket]) | ||||
idleUnits[bucket] = []; | idleUnits[bucket] = []; | ||||
idleUnits[bucket].push(entity); | idleUnits[bucket].push(entity); | ||||
// If enough units have been collected in the first bucket, go ahead and return them. | // If enough units have been collected in the first bucket, go ahead and return them. | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | if (data.target === firstMarket) | ||||
result = { | result = { | ||||
"type": "is first", | "type": "is first", | ||||
"hasBothMarkets": cmpEntityTrader.HasBothMarkets() | "hasBothMarkets": cmpEntityTrader.HasBothMarkets() | ||||
}; | }; | ||||
if (cmpEntityTrader.HasBothMarkets()) | if (cmpEntityTrader.HasBothMarkets()) | ||||
result.gain = cmpEntityTrader.GetGoods().amount; | result.gain = cmpEntityTrader.GetGoods().amount; | ||||
} | } | ||||
else if (data.target === secondMarket) | else if (data.target === secondMarket) | ||||
{ | |||||
result = { | result = { | ||||
"type": "is second", | "type": "is second", | ||||
"gain": cmpEntityTrader.GetGoods().amount, | "gain": cmpEntityTrader.GetGoods().amount, | ||||
}; | }; | ||||
} | |||||
else if (!firstMarket) | else if (!firstMarket) | ||||
{ | |||||
result = { "type": "set first" }; | result = { "type": "set first" }; | ||||
} | |||||
else if (!secondMarket) | else if (!secondMarket) | ||||
{ | |||||
result = { | result = { | ||||
"type": "set second", | "type": "set second", | ||||
"gain": cmpEntityTrader.CalculateGain(firstMarket, data.target), | "gain": cmpEntityTrader.CalculateGain(firstMarket, data.target), | ||||
}; | }; | ||||
} | |||||
else | |||||
{ | |||||
// Else both markets are not null and target is different from them | // Else both markets are not null and target is different from them | ||||
SilierUnsubmitted Done Inline ActionsYou need to decide if you put those type of comments above else, under else or at the line of next instruction Silier: You need to decide if you put those type of comments above else, under else or at the line of… | |||||
else | |||||
result = { "type": "set first" }; | result = { "type": "set first" }; | ||||
} | |||||
return result; | return result; | ||||
}; | }; | ||||
GuiInterface.prototype.CanAttack = function(player, data) | GuiInterface.prototype.CanAttack = function(player, data) | ||||
{ | { | ||||
let cmpAttack = Engine.QueryInterface(data.entity, IID_Attack); | let cmpAttack = Engine.QueryInterface(data.entity, IID_Attack); | ||||
return cmpAttack && cmpAttack.CanAttack(data.target, data.types || undefined); | return cmpAttack && cmpAttack.CanAttack(data.target, data.types || undefined); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 171 Lines • Show Last 20 Lines |
-ized
Usually I don't mind whether people use American or British spelling in comments, but using both in the same sentence is ugly.