Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/Player.js
Show All 11 Lines | "<element name='BarterMultiplier' a:help='Multipliers for barter prices.'>" + | ||||
"</interleave>" + | "</interleave>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='Formations' a:help='Space-separated list of formations this player can use.'>" + | "<element name='Formations' a:help='Space-separated list of formations this player can use.'>" + | ||||
"<attribute name='datatype'>" + | "<attribute name='datatype'>" + | ||||
"<value>tokens</value>" + | "<value>tokens</value>" + | ||||
"</attribute>" + | "</attribute>" + | ||||
"<text/>" + | "<text/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='SharedLosTech' a:help='Allies will share los when this technology is researched. Leave empty to never share LOS.'>" + | |||||
"<text/>" + | |||||
"</element>" + | |||||
"<element name='SharedDropsitesTech' a:help='Allies will share dropsites when this technology is researched. Leave empty to never share dropsites.'>" + | |||||
"<text/>" + | |||||
"</element>" + | |||||
"<element name='SpyCostMultiplier'>" + | "<element name='SpyCostMultiplier'>" + | ||||
"<ref name='nonNegativeDecimal'/>" + | "<ref name='nonNegativeDecimal'/>" + | ||||
"</element>"; | "</element>"; | ||||
// The GUI expects these strings. | // The GUI expects these strings. | ||||
Player.prototype.STATE_ACTIVE = "active"; | Player.prototype.STATE_ACTIVE = "active"; | ||||
Player.prototype.STATE_DEFEATED = "defeated"; | Player.prototype.STATE_DEFEATED = "defeated"; | ||||
Player.prototype.STATE_WON = "won"; | Player.prototype.STATE_WON = "won"; | ||||
/** | |||||
* Don't serialize diplomacyColor or displayDiplomacyColor since they're modified by the GUI. | |||||
*/ | |||||
Player.prototype.Serialize = function() | Player.prototype.Serialize = function() | ||||
{ | { | ||||
let state = {}; | let state = {}; | ||||
for (let key in this) | for (let key in this) | ||||
if (this.hasOwnProperty(key)) | if (this.hasOwnProperty(key)) | ||||
state[key] = this[key]; | state[key] = this[key]; | ||||
state.diplomacyColor = undefined; | // Modified by GUI, so don't serialise. | ||||
state.displayDiplomacyColor = false; | delete state.displayDiplomacyColor; | ||||
Stan: Could filter this in the loop above, but I suppose that's extra work. | |||||
return state; | return state; | ||||
}; | }; | ||||
Player.prototype.Deserialize = function(state) | Player.prototype.Deserialize = function(state) | ||||
{ | { | ||||
for (let prop in state) | for (let prop in state) | ||||
this[prop] = state[prop]; | this[prop] = state[prop]; | ||||
}; | }; | ||||
/** | /** | ||||
* Which units will be shown with special icons at the top. | * Which units will be shown with special icons at the top. | ||||
*/ | */ | ||||
var panelEntityClasses = "Hero Relic"; | var panelEntityClasses = "Hero Relic"; | ||||
Player.prototype.Init = function() | Player.prototype.Init = function() | ||||
{ | { | ||||
this.playerID = undefined; | this.playerID = undefined; | ||||
this.color = undefined; | this.color = undefined; | ||||
this.diplomacyColor = undefined; | |||||
this.displayDiplomacyColor = false; | |||||
this.popUsed = 0; // Population of units owned or trained by this player. | this.popUsed = 0; // Population of units owned or trained by this player. | ||||
this.popBonuses = 0; // Sum of population bonuses of player's entities. | this.popBonuses = 0; // Sum of population bonuses of player's entities. | ||||
this.maxPop = 300; // Maximum population. | this.maxPop = 300; // Maximum population. | ||||
this.trainingBlocked = false; // Indicates whether any training queue is currently blocked. | this.trainingBlocked = false; // Indicates whether any training queue is currently blocked. | ||||
this.resourceCount = {}; | this.resourceCount = {}; | ||||
this.resourceGatherers = {}; | this.resourceGatherers = {}; | ||||
this.tradingGoods = []; // Goods for next trade-route and its probabilities * 100. | this.tradingGoods = []; // Goods for next trade-route and its probabilities * 100. | ||||
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. | |||||
this.teamsLocked = false; | |||||
this.state = this.STATE_ACTIVE; | this.state = this.STATE_ACTIVE; | ||||
this.diplomacy = []; // Array of diplomatic stances for this player with respect to other players (including gaia and self). | |||||
this.sharedDropsites = false; | |||||
this.formations = this.template.Formations._string.split(" "); | this.formations = this.template.Formations._string.split(" "); | ||||
this.startCam = undefined; | this.startCam = undefined; | ||||
this.controlAllUnits = false; | this.controlAllUnits = false; | ||||
this.isAI = false; | this.isAI = false; | ||||
this.cheatsEnabled = false; | this.cheatsEnabled = false; | ||||
this.panelEntities = []; | this.panelEntities = []; | ||||
this.resourceNames = {}; | this.resourceNames = {}; | ||||
this.disabledTemplates = {}; | this.disabledTemplates = {}; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | Player.prototype.SetColor = function(r, g, b) | ||||
// Used in Atlas. | // Used in Atlas. | ||||
if (colorInitialized) | if (colorInitialized) | ||||
Engine.BroadcastMessage(MT_PlayerColorChanged, { | Engine.BroadcastMessage(MT_PlayerColorChanged, { | ||||
"player": this.playerID | "player": this.playerID | ||||
}); | }); | ||||
}; | }; | ||||
Player.prototype.SetDiplomacyColor = function(color) | |||||
{ | |||||
this.diplomacyColor = { "r": color.r / 255, "g": color.g / 255, "b": color.b / 255, "a": 1 }; | |||||
}; | |||||
Player.prototype.SetDisplayDiplomacyColor = function(displayDiplomacyColor) | Player.prototype.SetDisplayDiplomacyColor = function(displayDiplomacyColor) | ||||
{ | { | ||||
this.displayDiplomacyColor = displayDiplomacyColor; | this.displayDiplomacyColor = displayDiplomacyColor; | ||||
}; | }; | ||||
Player.prototype.GetColor = function() | Player.prototype.GetColor = function() | ||||
{ | { | ||||
return this.color; | return this.color; | ||||
}; | }; | ||||
Player.prototype.GetDisplayedColor = function() | Player.prototype.GetDisplayedColor = function() | ||||
{ | { | ||||
return this.displayDiplomacyColor ? this.diplomacyColor : this.color; | return this.displayDiplomacyColor ? Engine.QueryInterface(this.entity, IID_Diplomacy).GetColor() : this.color; | ||||
}; | }; | ||||
// Try reserving num population slots. Returns 0 on success or number of missing slots otherwise. | // Try reserving num population slots. Returns 0 on success or number of missing slots otherwise. | ||||
Player.prototype.TryReservePopulationSlots = function(num) | Player.prototype.TryReservePopulationSlots = function(num) | ||||
{ | { | ||||
if (num != 0 && num > (this.GetPopulationLimit() - this.popUsed)) | if (num != 0 && num > (this.GetPopulationLimit() - this.popUsed)) | ||||
return num - (this.GetPopulationLimit() - this.popUsed); | return num - (this.GetPopulationLimit() - this.popUsed); | ||||
▲ Show 20 Lines • Show All 375 Lines • ▼ Show 20 Lines | Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).PushNotification({ | ||||
"players": [this.playerID], | "players": [this.playerID], | ||||
"allies": [this.playerID], | "allies": [this.playerID], | ||||
"message": message | "message": message | ||||
}); | }); | ||||
Engine.PostMessage(this.entity, won ? MT_PlayerWon : MT_PlayerDefeated, { "playerId": this.playerID }); | Engine.PostMessage(this.entity, won ? MT_PlayerWon : MT_PlayerDefeated, { "playerId": this.playerID }); | ||||
}; | }; | ||||
Player.prototype.GetTeam = function() | |||||
{ | |||||
return this.team; | |||||
}; | |||||
Player.prototype.SetTeam = function(team) | |||||
{ | |||||
if (this.teamsLocked) | |||||
return; | |||||
this.team = team; | |||||
// Set all team members as allies. | |||||
if (this.team != -1) | |||||
{ | |||||
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); | |||||
for (let i = 0; i < numPlayers; ++i) | |||||
{ | |||||
let cmpPlayer = QueryPlayerIDInterface(i); | |||||
if (this.team != cmpPlayer.GetTeam()) | |||||
continue; | |||||
this.SetAlly(i); | |||||
cmpPlayer.SetAlly(this.playerID); | |||||
} | |||||
} | |||||
Engine.BroadcastMessage(MT_DiplomacyChanged, { | |||||
"player": this.playerID, | |||||
"otherPlayer": null | |||||
}); | |||||
}; | |||||
Player.prototype.SetLockTeams = function(value) | |||||
{ | |||||
this.teamsLocked = value; | |||||
}; | |||||
Player.prototype.GetLockTeams = function() | |||||
{ | |||||
return this.teamsLocked; | |||||
}; | |||||
Player.prototype.GetDiplomacy = function() | |||||
{ | |||||
return this.diplomacy.slice(); | |||||
}; | |||||
Player.prototype.SetDiplomacy = function(dipl) | |||||
{ | |||||
this.diplomacy = dipl.slice(); | |||||
Engine.BroadcastMessage(MT_DiplomacyChanged, { | |||||
"player": this.playerID, | |||||
"otherPlayer": null | |||||
}); | |||||
}; | |||||
Player.prototype.SetDiplomacyIndex = function(idx, value) | |||||
{ | |||||
let cmpPlayer = QueryPlayerIDInterface(idx); | |||||
if (!cmpPlayer) | |||||
return; | |||||
if (!this.IsActive() || !cmpPlayer.IsActive()) | |||||
return; | |||||
this.diplomacy[idx] = value; | |||||
Engine.BroadcastMessage(MT_DiplomacyChanged, { | |||||
"player": this.playerID, | |||||
"otherPlayer": cmpPlayer.GetPlayerID() | |||||
}); | |||||
// Mutual worsening of relations. | |||||
if (cmpPlayer.diplomacy[this.playerID] > value) | |||||
cmpPlayer.SetDiplomacyIndex(this.playerID, value); | |||||
}; | |||||
Player.prototype.UpdateSharedLos = function() | |||||
{ | |||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | |||||
let cmpTechnologyManager = Engine.QueryInterface(this.entity, IID_TechnologyManager); | |||||
if (!cmpRangeManager || !cmpTechnologyManager) | |||||
return; | |||||
if (!cmpTechnologyManager.IsTechnologyResearched(this.template.SharedLosTech)) | |||||
{ | |||||
cmpRangeManager.SetSharedLos(this.playerID, [this.playerID]); | |||||
return; | |||||
} | |||||
cmpRangeManager.SetSharedLos(this.playerID, this.GetMutualAllies()); | |||||
}; | |||||
Player.prototype.GetFormations = function() | Player.prototype.GetFormations = function() | ||||
{ | { | ||||
return this.formations; | return this.formations; | ||||
}; | }; | ||||
Player.prototype.SetFormations = function(formations) | Player.prototype.SetFormations = function(formations) | ||||
{ | { | ||||
this.formations = formations; | this.formations = formations; | ||||
Show All 14 Lines | Player.prototype.SetStartingCamera = function(pos, rot) | ||||
this.startCam = { "position": pos, "rotation": rot }; | this.startCam = { "position": pos, "rotation": rot }; | ||||
}; | }; | ||||
Player.prototype.HasStartingCamera = function() | Player.prototype.HasStartingCamera = function() | ||||
{ | { | ||||
return this.startCam !== undefined; | return this.startCam !== undefined; | ||||
}; | }; | ||||
Player.prototype.HasSharedLos = function() | |||||
{ | |||||
let cmpTechnologyManager = Engine.QueryInterface(this.entity, IID_TechnologyManager); | |||||
return cmpTechnologyManager && cmpTechnologyManager.IsTechnologyResearched(this.template.SharedLosTech); | |||||
}; | |||||
Player.prototype.HasSharedDropsites = function() | |||||
{ | |||||
return this.sharedDropsites; | |||||
}; | |||||
Player.prototype.SetControlAllUnits = function(c) | Player.prototype.SetControlAllUnits = function(c) | ||||
{ | { | ||||
this.controlAllUnits = c; | this.controlAllUnits = c; | ||||
}; | }; | ||||
Player.prototype.CanControlAllUnits = function() | Player.prototype.CanControlAllUnits = function() | ||||
{ | { | ||||
return this.controlAllUnits; | return this.controlAllUnits; | ||||
}; | }; | ||||
Player.prototype.SetAI = function(flag) | Player.prototype.SetAI = function(flag) | ||||
{ | { | ||||
this.isAI = flag; | this.isAI = flag; | ||||
}; | }; | ||||
Player.prototype.IsAI = function() | Player.prototype.IsAI = function() | ||||
{ | { | ||||
return this.isAI; | return this.isAI; | ||||
}; | }; | ||||
Player.prototype.GetPlayersByDiplomacy = function(func) | |||||
{ | |||||
let players = []; | |||||
for (let i = 0; i < this.diplomacy.length; ++i) | |||||
if (this[func](i)) | |||||
players.push(i); | |||||
return players; | |||||
}; | |||||
Player.prototype.SetAlly = function(id) | |||||
{ | |||||
this.SetDiplomacyIndex(id, 1); | |||||
}; | |||||
/** | |||||
* Check if given player is our ally. | |||||
*/ | |||||
Player.prototype.IsAlly = function(id) | |||||
{ | |||||
return this.diplomacy[id] > 0; | |||||
}; | |||||
Player.prototype.GetAllies = function() | |||||
{ | |||||
return this.GetPlayersByDiplomacy("IsAlly"); | |||||
}; | |||||
/** | |||||
* Check if given player is our ally excluding ourself | |||||
*/ | |||||
Player.prototype.IsExclusiveAlly = function(id) | |||||
{ | |||||
return this.playerID != id && this.IsAlly(id); | |||||
}; | |||||
/** | |||||
* Check if given player is our ally, and we are its ally | |||||
*/ | |||||
Player.prototype.IsMutualAlly = function(id) | |||||
{ | |||||
let cmpPlayer = QueryPlayerIDInterface(id); | |||||
return this.IsAlly(id) && cmpPlayer && cmpPlayer.IsAlly(this.playerID); | |||||
}; | |||||
Player.prototype.GetMutualAllies = function() | |||||
{ | |||||
return this.GetPlayersByDiplomacy("IsMutualAlly"); | |||||
}; | |||||
/** | |||||
* Check if given player is our ally, and we are its ally, excluding ourself | |||||
*/ | |||||
Player.prototype.IsExclusiveMutualAlly = function(id) | |||||
{ | |||||
return this.playerID != id && this.IsMutualAlly(id); | |||||
}; | |||||
Player.prototype.SetEnemy = function(id) | |||||
{ | |||||
this.SetDiplomacyIndex(id, -1); | |||||
}; | |||||
/** | |||||
* Check if given player is our enemy | |||||
*/ | |||||
Player.prototype.IsEnemy = function(id) | |||||
{ | |||||
return this.diplomacy[id] < 0; | |||||
}; | |||||
Player.prototype.GetEnemies = function() | |||||
{ | |||||
return this.GetPlayersByDiplomacy("IsEnemy"); | |||||
}; | |||||
Player.prototype.SetNeutral = function(id) | |||||
{ | |||||
this.SetDiplomacyIndex(id, 0); | |||||
}; | |||||
/** | |||||
* Check if given player is neutral | |||||
*/ | |||||
Player.prototype.IsNeutral = function(id) | |||||
{ | |||||
return this.diplomacy[id] == 0; | |||||
}; | |||||
/** | /** | ||||
* Do some map dependant initializations | * Do some map dependant initializations | ||||
*/ | */ | ||||
Player.prototype.OnGlobalInitGame = function(msg) | Player.prototype.OnGlobalInitGame = function(msg) | ||||
{ | { | ||||
// Replace the "{civ}" code with this civ ID. | // Replace the "{civ}" code with this civ ID. | ||||
let disabledTemplates = this.disabledTemplates; | let disabledTemplates = this.disabledTemplates; | ||||
this.disabledTemplates = {}; | this.disabledTemplates = {}; | ||||
Show All 39 Lines | if (msg.to == this.playerID) | ||||
if (MatchesClassList(cmpIdentity.GetClassesList(), panelEntityClasses)) | if (MatchesClassList(cmpIdentity.GetClassesList(), panelEntityClasses)) | ||||
this.panelEntities.push(msg.entity); | this.panelEntities.push(msg.entity); | ||||
if (cmpIdentity.HasClass("Barter") && !Engine.QueryInterface(msg.entity, IID_Foundation)) | if (cmpIdentity.HasClass("Barter") && !Engine.QueryInterface(msg.entity, IID_Foundation)) | ||||
this.barterEntities.push(msg.entity); | this.barterEntities.push(msg.entity); | ||||
} | } | ||||
}; | }; | ||||
Player.prototype.OnResearchFinished = function(msg) | |||||
{ | |||||
if (msg.tech == this.template.SharedLosTech) | |||||
this.UpdateSharedLos(); | |||||
else if (msg.tech == this.template.SharedDropsitesTech) | |||||
this.sharedDropsites = true; | |||||
}; | |||||
Player.prototype.OnDiplomacyChanged = function() | |||||
{ | |||||
this.UpdateSharedLos(); | |||||
}; | |||||
Player.prototype.OnValueModification = function(msg) | Player.prototype.OnValueModification = function(msg) | ||||
{ | { | ||||
if (msg.component != "Player") | if (msg.component != "Player") | ||||
return; | return; | ||||
if (msg.valueNames.indexOf("Player/SpyCostMultiplier") != -1) | if (msg.valueNames.indexOf("Player/SpyCostMultiplier") != -1) | ||||
this.spyCostMultiplier = ApplyValueModificationsToEntity("Player/SpyCostMultiplier", +this.template.SpyCostMultiplier, this.entity); | this.spyCostMultiplier = ApplyValueModificationsToEntity("Player/SpyCostMultiplier", +this.template.SpyCostMultiplier, this.entity); | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
Player.prototype.OnGlobalPlayerDefeated = function(msg) | Player.prototype.OnGlobalPlayerDefeated = function(msg) | ||||
{ | { | ||||
let cmpSound = Engine.QueryInterface(this.entity, IID_Sound); | let cmpSound = Engine.QueryInterface(this.entity, IID_Sound); | ||||
if (!cmpSound) | if (!cmpSound) | ||||
return; | return; | ||||
const soundGroup = cmpSound.GetSoundGroup(this.playerID === msg.playerId ? "defeated" : this.IsAlly(msg.playerId) ? "defeated_ally" : this.HasWon() ? "won" : "defeated_enemy"); | const soundGroup = cmpSound.GetSoundGroup(this.playerID === msg.playerId ? "defeated" : this.HasWon() ? "won" : ""); | ||||
if (soundGroup) | if (soundGroup) | ||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager).PlaySoundGroupForPlayer(soundGroup, this.playerID); | Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager).PlaySoundGroupForPlayer(soundGroup, this.playerID); | ||||
}; | }; | ||||
Engine.RegisterComponentType(IID_Player, "Player", Player); | Engine.RegisterComponentType(IID_Player, "Player", Player); |
Wildfire Games · Phabricator
Could filter this in the loop above, but I suppose that's extra work.