mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-07-25 12:52:36 +00:00
93ce94655d
Up to now `eslint-plugin-brace-rules` was used to enforce a common brace style for JavaScript code. This plugin was however updated the last time over 9 years ago and will be incompatible with ESLint v10, as that [removes `context.getSourceCode()`][1], the plugin relies on. To keep the eslint config working with ESLint v10, this replaces `eslint-plugin-brace-rules` with the [`@stylistic/brace-style`][2] rule from `@stylistic/eslint-plugin`, a package we already use. While `@stylistic/brace-style` doesn't offer an option to format braces in exactly the same way as before, the "allman" style seems to be the one closest to the existing code. [1]: https://eslint.org/blog/2025/11/eslint-v10.0.0-alpha.0-released/#removed-deprecated-rule-context-members [2]: https://eslint.style/rules/brace-style
286 lines
9.0 KiB
JavaScript
286 lines
9.0 KiB
JavaScript
/**
|
|
* Used to create player entities prior to reading the rest of a map,
|
|
* all other initialization must be done after loading map (terrain/entities).
|
|
* Be VERY careful in using other components here, as they may not be properly initialised yet.
|
|
* settings is the object containing settings for this map.
|
|
* newPlayers if true will remove old player entities or add new ones until
|
|
* the new number of player entities is obtained
|
|
* (used when loading a map or when Atlas changes the number of players).
|
|
*/
|
|
function LoadPlayerSettings(settings, newPlayers)
|
|
{
|
|
const playerDefaults = Engine.ReadJSONFile("simulation/data/settings/player_defaults.json").PlayerData;
|
|
const playerData = settings.PlayerData;
|
|
if (!playerData)
|
|
warn("Player.js: Setup has no player data - using defaults.");
|
|
|
|
const getPlayerSetting = (idx, property) =>
|
|
{
|
|
if (playerData && playerData[idx] && (property in playerData[idx]))
|
|
return playerData[idx][property];
|
|
|
|
if (playerDefaults && playerDefaults[idx] && (property in playerDefaults[idx]))
|
|
return playerDefaults[idx][property];
|
|
|
|
return undefined;
|
|
};
|
|
|
|
// Add gaia to simplify iteration
|
|
// (if gaia is not already the first civ such as when called from Atlas' ActorViewer)
|
|
if (playerData && playerData[0] && (!playerData[0].Civ || playerData[0].Civ != "gaia"))
|
|
playerData.unshift(null);
|
|
|
|
if (playerData && !playerData.some(v => v && !!v.AI))
|
|
Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface).Disable();
|
|
|
|
const cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
|
let numPlayers = cmpPlayerManager.GetNumPlayers();
|
|
|
|
// Remove existing players or add new ones
|
|
if (newPlayers)
|
|
{
|
|
const settingsNumPlayers = playerData?.length ?? playerDefaults.length;
|
|
|
|
while (numPlayers < settingsNumPlayers)
|
|
cmpPlayerManager.AddPlayer(GetPlayerTemplateName(getPlayerSetting(numPlayers++, "Civ")));
|
|
|
|
for (; numPlayers > settingsNumPlayers; numPlayers--)
|
|
cmpPlayerManager.RemoveLastPlayer();
|
|
}
|
|
|
|
// Even when no new player, we must check the template compatibility as player templates are civ dependent.
|
|
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
|
for (let i = 0; i < numPlayers; ++i)
|
|
{
|
|
const template = GetPlayerTemplateName(getPlayerSetting(i, "Civ"));
|
|
const entID = cmpPlayerManager.GetPlayerByID(i);
|
|
if (cmpTemplateManager.GetCurrentTemplateName(entID) !== template)
|
|
cmpPlayerManager.ReplacePlayerTemplate(i, template);
|
|
}
|
|
|
|
for (let i = 0; i < numPlayers; ++i)
|
|
{
|
|
QueryPlayerIDInterface(i, IID_Identity).SetName(getPlayerSetting(i, "Name"));
|
|
|
|
const color = getPlayerSetting(i, "Color");
|
|
const cmpPlayer = QueryPlayerIDInterface(i);
|
|
cmpPlayer.SetColor(color.r, color.g, color.b);
|
|
|
|
// Special case for gaia
|
|
if (i === 0)
|
|
continue;
|
|
|
|
// Atlas has no information about player removal.
|
|
cmpPlayer.SetRemoved(getPlayerSetting(i, "Removed") === true);
|
|
|
|
// StartingResources
|
|
if (settings.PlayerData[i].Resources !== undefined)
|
|
cmpPlayer.SetResourceCounts(settings.PlayerData[i].Resources);
|
|
else if (settings.StartingResources)
|
|
{
|
|
const resourceCounts = cmpPlayer.GetResourceCounts();
|
|
const newResourceCounts = {};
|
|
for (const resources in resourceCounts)
|
|
newResourceCounts[resources] = settings.StartingResources;
|
|
cmpPlayer.SetResourceCounts(newResourceCounts);
|
|
}
|
|
else if (playerDefaults[i].Resources !== undefined)
|
|
cmpPlayer.SetResourceCounts(playerDefaults[i].Resources);
|
|
|
|
if (settings.DisableSpies)
|
|
{
|
|
cmpPlayer.AddDisabledTechnology("unlock_spies");
|
|
cmpPlayer.AddDisabledTemplate("special/spy");
|
|
}
|
|
|
|
// If diplomacy explicitly defined, use that; otherwise use teams.
|
|
const diplomacy = getPlayerSetting(i, "Diplomacy");
|
|
if (diplomacy !== undefined)
|
|
QueryPlayerIDInterface(i, IID_Diplomacy).SetDiplomacy(diplomacy);
|
|
else
|
|
QueryPlayerIDInterface(i, IID_Diplomacy).ChangeTeam(getPlayerSetting(i, "Team") ?? -1);
|
|
|
|
const formations = getPlayerSetting(i, "Formations");
|
|
if (formations)
|
|
cmpPlayer.SetFormations(formations);
|
|
|
|
const startCam = getPlayerSetting(i, "StartingCamera");
|
|
if (startCam)
|
|
cmpPlayer.SetStartingCamera(startCam.Position, startCam.Rotation);
|
|
}
|
|
|
|
// NOTE: We need to do the team locking here, as
|
|
// otherwise we can't ally the players above.
|
|
if (settings.LockTeams)
|
|
for (let i = 0; i < numPlayers; ++i)
|
|
QueryPlayerIDInterface(i, IID_Diplomacy).LockTeam();
|
|
}
|
|
|
|
function GetPlayerTemplateName(civ)
|
|
{
|
|
return "special/players/" + civ;
|
|
}
|
|
|
|
/**
|
|
* @param id An entity's ID
|
|
* @returns The entity ID of the owner player (not his player ID) or ent if ent is a player entity.
|
|
*/
|
|
function QueryOwnerEntityID(ent)
|
|
{
|
|
const cmpPlayer = Engine.QueryInterface(ent, IID_Player);
|
|
if (cmpPlayer)
|
|
return ent;
|
|
|
|
const cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
|
if (!cmpOwnership)
|
|
return null;
|
|
|
|
const owner = cmpOwnership.GetOwner();
|
|
if (owner == INVALID_PLAYER)
|
|
return null;
|
|
|
|
const cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
|
if (!cmpPlayerManager)
|
|
return null;
|
|
|
|
return cmpPlayerManager.GetPlayerByID(owner);
|
|
}
|
|
|
|
/**
|
|
* Similar to Engine.QueryInterface but applies to the player entity
|
|
* that owns the given entity.
|
|
* iid is typically IID_Player.
|
|
*/
|
|
function QueryOwnerInterface(ent, iid = IID_Player)
|
|
{
|
|
var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
|
if (!cmpOwnership)
|
|
return null;
|
|
|
|
var owner = cmpOwnership.GetOwner();
|
|
if (owner == INVALID_PLAYER)
|
|
return null;
|
|
|
|
return QueryPlayerIDInterface(owner, iid);
|
|
}
|
|
|
|
/**
|
|
* Similar to Engine.QueryInterface but applies to the player entity
|
|
* with the given ID number.
|
|
* iid is typically IID_Player.
|
|
*/
|
|
function QueryPlayerIDInterface(id, iid = IID_Player)
|
|
{
|
|
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
|
|
|
var playerEnt = cmpPlayerManager.GetPlayerByID(id);
|
|
if (!playerEnt)
|
|
return null;
|
|
|
|
return Engine.QueryInterface(playerEnt, iid);
|
|
}
|
|
|
|
/**
|
|
* Similar to Engine.QueryInterface but first checks if the entity
|
|
* mirages the interface.
|
|
*/
|
|
function QueryMiragedInterface(ent, iid)
|
|
{
|
|
const cmpMirage = Engine.QueryInterface(ent, IID_Mirage);
|
|
if (cmpMirage && !cmpMirage.Mirages(iid))
|
|
return null;
|
|
else if (!cmpMirage)
|
|
return Engine.QueryInterface(ent, iid);
|
|
|
|
return cmpMirage.Get(iid);
|
|
}
|
|
|
|
/**
|
|
* Similar to Engine.QueryInterface, but checks for all interfaces
|
|
* implementing a builder list (currently Foundation and Repairable)
|
|
* TODO Foundation and Repairable could both implement a BuilderList component
|
|
*/
|
|
function QueryBuilderListInterface(ent)
|
|
{
|
|
return Engine.QueryInterface(ent, IID_Foundation) || Engine.QueryInterface(ent, IID_Repairable);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the entity 'target' is owned by an ally of
|
|
* the owner of 'entity'.
|
|
*/
|
|
function IsOwnedByAllyOfEntity(entity, target)
|
|
{
|
|
return IsOwnedByEntityHelper(entity, target, "IsAlly");
|
|
}
|
|
|
|
function IsOwnedByMutualAllyOfEntity(entity, target)
|
|
{
|
|
return IsOwnedByEntityHelper(entity, target, "IsMutualAlly");
|
|
}
|
|
|
|
function IsOwnedByEntityHelper(entity, target, check)
|
|
{
|
|
const owner = Engine.QueryInterface(entity, IID_Ownership)?.GetOwner() || 0;
|
|
return IsOwnedByHelper(owner, target, check);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the entity 'target' is owned by player
|
|
*/
|
|
function IsOwnedByPlayer(player, target)
|
|
{
|
|
var cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
|
|
return cmpOwnershipTarget && player == cmpOwnershipTarget.GetOwner();
|
|
}
|
|
|
|
function IsOwnedByGaia(target)
|
|
{
|
|
return IsOwnedByPlayer(0, target);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the entity 'target' is owned by an ally of player
|
|
*/
|
|
function IsOwnedByAllyOfPlayer(player, target)
|
|
{
|
|
return IsOwnedByHelper(player, target, "IsAlly");
|
|
}
|
|
|
|
function IsOwnedByMutualAllyOfPlayer(player, target)
|
|
{
|
|
return IsOwnedByHelper(player, target, "IsMutualAlly");
|
|
}
|
|
|
|
function IsOwnedByNeutralOfPlayer(player, target)
|
|
{
|
|
return IsOwnedByHelper(player, target, "IsNeutral");
|
|
}
|
|
|
|
function IsOwnedByEnemyOfPlayer(player, target)
|
|
{
|
|
return IsOwnedByHelper(player, target, "IsEnemy");
|
|
}
|
|
|
|
function IsOwnedByHelper(player, target, check)
|
|
{
|
|
const targetOwner = Engine.QueryInterface(target, IID_Ownership)?.GetOwner() || 0;
|
|
const cmpDiplomacy = QueryPlayerIDInterface(player, IID_Diplomacy);
|
|
return cmpDiplomacy && cmpDiplomacy[check](targetOwner);
|
|
}
|
|
|
|
Engine.RegisterGlobal("LoadPlayerSettings", LoadPlayerSettings);
|
|
Engine.RegisterGlobal("QueryOwnerEntityID", QueryOwnerEntityID);
|
|
Engine.RegisterGlobal("QueryOwnerInterface", QueryOwnerInterface);
|
|
Engine.RegisterGlobal("QueryPlayerIDInterface", QueryPlayerIDInterface);
|
|
Engine.RegisterGlobal("QueryMiragedInterface", QueryMiragedInterface);
|
|
Engine.RegisterGlobal("QueryBuilderListInterface", QueryBuilderListInterface);
|
|
Engine.RegisterGlobal("IsOwnedByAllyOfEntity", IsOwnedByAllyOfEntity);
|
|
Engine.RegisterGlobal("IsOwnedByMutualAllyOfEntity", IsOwnedByMutualAllyOfEntity);
|
|
Engine.RegisterGlobal("IsOwnedByPlayer", IsOwnedByPlayer);
|
|
Engine.RegisterGlobal("IsOwnedByGaia", IsOwnedByGaia);
|
|
Engine.RegisterGlobal("IsOwnedByAllyOfPlayer", IsOwnedByAllyOfPlayer);
|
|
Engine.RegisterGlobal("IsOwnedByMutualAllyOfPlayer", IsOwnedByMutualAllyOfPlayer);
|
|
Engine.RegisterGlobal("IsOwnedByNeutralOfPlayer", IsOwnedByNeutralOfPlayer);
|
|
Engine.RegisterGlobal("IsOwnedByEnemyOfPlayer", IsOwnedByEnemyOfPlayer);
|