Line data Source code
1 : /**
2 : * Used to create player entities prior to reading the rest of a map,
3 : * all other initialization must be done after loading map (terrain/entities).
4 : * Be VERY careful in using other components here, as they may not be properly initialised yet.
5 : * settings is the object containing settings for this map.
6 : * newPlayers if true will remove old player entities or add new ones until
7 : * the new number of player entities is obtained
8 : * (used when loading a map or when Atlas changes the number of players).
9 : */
10 : function LoadPlayerSettings(settings, newPlayers)
11 : {
12 0 : const playerDefaults = Engine.ReadJSONFile("simulation/data/settings/player_defaults.json").PlayerData;
13 0 : const playerData = settings.PlayerData;
14 0 : if (!playerData)
15 0 : warn("Player.js: Setup has no player data - using defaults.");
16 :
17 0 : const getPlayerSetting = (idx, property) => {
18 0 : if (playerData && playerData[idx] && (property in playerData[idx]))
19 0 : return playerData[idx][property];
20 :
21 0 : if (playerDefaults && playerDefaults[idx] && (property in playerDefaults[idx]))
22 0 : return playerDefaults[idx][property];
23 :
24 0 : return undefined;
25 : };
26 :
27 : // Add gaia to simplify iteration
28 : // (if gaia is not already the first civ such as when called from Atlas' ActorViewer)
29 0 : if (playerData && playerData[0] && (!playerData[0].Civ || playerData[0].Civ != "gaia"))
30 0 : playerData.unshift(null);
31 :
32 0 : if (playerData && !playerData.some(v => v && !!v.AI))
33 0 : Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface).Disable();
34 :
35 0 : const cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
36 0 : let numPlayers = cmpPlayerManager.GetNumPlayers();
37 :
38 : // Remove existing players or add new ones
39 0 : if (newPlayers)
40 : {
41 0 : const settingsNumPlayers = playerData?.length ?? playerDefaults.length;
42 :
43 0 : while (numPlayers < settingsNumPlayers)
44 0 : cmpPlayerManager.AddPlayer(GetPlayerTemplateName(getPlayerSetting(numPlayers++, "Civ")));
45 :
46 0 : for (; numPlayers > settingsNumPlayers; numPlayers--)
47 0 : cmpPlayerManager.RemoveLastPlayer();
48 : }
49 :
50 : // Even when no new player, we must check the template compatibility as player templates are civ dependent.
51 0 : const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
52 0 : for (let i = 0; i < numPlayers; ++i)
53 : {
54 0 : const template = GetPlayerTemplateName(getPlayerSetting(i, "Civ"));
55 0 : const entID = cmpPlayerManager.GetPlayerByID(i);
56 0 : if (cmpTemplateManager.GetCurrentTemplateName(entID) !== template)
57 0 : cmpPlayerManager.ReplacePlayerTemplate(i, template);
58 : }
59 :
60 0 : for (let i = 0; i < numPlayers; ++i)
61 : {
62 0 : QueryPlayerIDInterface(i, IID_Identity).SetName(getPlayerSetting(i, "Name"));
63 :
64 0 : const color = getPlayerSetting(i, "Color");
65 0 : const cmpPlayer = QueryPlayerIDInterface(i);
66 0 : cmpPlayer.SetColor(color.r, color.g, color.b);
67 :
68 : // Special case for gaia
69 0 : if (i == 0)
70 0 : continue;
71 :
72 : // PopulationLimit
73 : {
74 : const maxPopulation =
75 0 : settings.PlayerData[i].PopulationLimit !== undefined ?
76 : settings.PlayerData[i].PopulationLimit :
77 : settings.PopulationCap !== undefined ?
78 : settings.PopulationCap :
79 : playerDefaults[i].PopulationLimit !== undefined ?
80 : playerDefaults[i].PopulationLimit :
81 : undefined;
82 :
83 0 : if (maxPopulation !== undefined)
84 0 : cmpPlayer.SetMaxPopulation(maxPopulation);
85 : }
86 :
87 : // StartingResources
88 0 : if (settings.PlayerData[i].Resources !== undefined)
89 0 : cmpPlayer.SetResourceCounts(settings.PlayerData[i].Resources);
90 0 : else if (settings.StartingResources)
91 : {
92 0 : let resourceCounts = cmpPlayer.GetResourceCounts();
93 0 : let newResourceCounts = {};
94 0 : for (let resouces in resourceCounts)
95 0 : newResourceCounts[resouces] = settings.StartingResources;
96 0 : cmpPlayer.SetResourceCounts(newResourceCounts);
97 : }
98 0 : else if (playerDefaults[i].Resources !== undefined)
99 0 : cmpPlayer.SetResourceCounts(playerDefaults[i].Resources);
100 :
101 0 : if (settings.DisableSpies)
102 : {
103 0 : cmpPlayer.AddDisabledTechnology("unlock_spies");
104 0 : cmpPlayer.AddDisabledTemplate("special/spy");
105 : }
106 :
107 : // If diplomacy explicitly defined, use that; otherwise use teams.
108 0 : const diplomacy = getPlayerSetting(i, "Diplomacy");
109 0 : if (diplomacy !== undefined)
110 0 : cmpPlayer.SetDiplomacy(diplomacy);
111 : else
112 0 : cmpPlayer.SetTeam(getPlayerSetting(i, "Team") ?? -1);
113 :
114 0 : const formations = getPlayerSetting(i, "Formations");
115 0 : if (formations)
116 0 : cmpPlayer.SetFormations(formations);
117 :
118 0 : const startCam = getPlayerSetting(i, "StartingCamera");
119 0 : if (startCam)
120 0 : cmpPlayer.SetStartingCamera(startCam.Position, startCam.Rotation);
121 : }
122 :
123 : // NOTE: We need to do the team locking here, as otherwise
124 : // SetTeam can't ally the players.
125 0 : if (settings.LockTeams)
126 0 : for (let i = 0; i < numPlayers; ++i)
127 0 : QueryPlayerIDInterface(i).SetLockTeams(true);
128 : }
129 :
130 : function GetPlayerTemplateName(civ)
131 : {
132 0 : return "special/players/" + civ;
133 : }
134 :
135 : /**
136 : * @param id An entity's ID
137 : * @returns The entity ID of the owner player (not his player ID) or ent if ent is a player entity.
138 : */
139 : function QueryOwnerEntityID(ent)
140 : {
141 37 : let cmpPlayer = Engine.QueryInterface(ent, IID_Player);
142 37 : if (cmpPlayer)
143 3 : return ent;
144 :
145 34 : let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
146 34 : if (!cmpOwnership)
147 6 : return null;
148 :
149 28 : let owner = cmpOwnership.GetOwner();
150 28 : if (owner == INVALID_PLAYER)
151 0 : return null;
152 :
153 28 : let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
154 28 : if (!cmpPlayerManager)
155 0 : return null;
156 :
157 28 : return cmpPlayerManager.GetPlayerByID(owner);
158 : }
159 :
160 : /**
161 : * Similar to Engine.QueryInterface but applies to the player entity
162 : * that owns the given entity.
163 : * iid is typically IID_Player.
164 : */
165 : function QueryOwnerInterface(ent, iid = IID_Player)
166 : {
167 372 : var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
168 372 : if (!cmpOwnership)
169 2 : return null;
170 :
171 370 : var owner = cmpOwnership.GetOwner();
172 370 : if (owner == INVALID_PLAYER)
173 1 : return null;
174 :
175 369 : return QueryPlayerIDInterface(owner, iid);
176 : }
177 :
178 : /**
179 : * Similar to Engine.QueryInterface but applies to the player entity
180 : * with the given ID number.
181 : * iid is typically IID_Player.
182 : */
183 : function QueryPlayerIDInterface(id, iid = IID_Player)
184 : {
185 630 : var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
186 :
187 630 : var playerEnt = cmpPlayerManager.GetPlayerByID(id);
188 630 : if (!playerEnt)
189 0 : return null;
190 :
191 630 : return Engine.QueryInterface(playerEnt, iid);
192 : }
193 :
194 : /**
195 : * Similar to Engine.QueryInterface but first checks if the entity
196 : * mirages the interface.
197 : */
198 : function QueryMiragedInterface(ent, iid)
199 : {
200 612 : let cmpMirage = Engine.QueryInterface(ent, IID_Mirage);
201 612 : if (cmpMirage && !cmpMirage.Mirages(iid))
202 0 : return null;
203 612 : else if (!cmpMirage)
204 612 : return Engine.QueryInterface(ent, iid);
205 :
206 0 : return cmpMirage.Get(iid);
207 : }
208 :
209 : /**
210 : * Similar to Engine.QueryInterface, but checks for all interfaces
211 : * implementing a builder list (currently Foundation and Repairable)
212 : * TODO Foundation and Repairable could both implement a BuilderList component
213 : */
214 : function QueryBuilderListInterface(ent)
215 : {
216 4 : return Engine.QueryInterface(ent, IID_Foundation) || Engine.QueryInterface(ent, IID_Repairable);
217 : }
218 :
219 : /**
220 : * Returns true if the entity 'target' is owned by an ally of
221 : * the owner of 'entity'.
222 : */
223 : function IsOwnedByAllyOfEntity(entity, target)
224 : {
225 0 : return IsOwnedByEntityHelper(entity, target, "IsAlly");
226 : }
227 :
228 : function IsOwnedByMutualAllyOfEntity(entity, target)
229 : {
230 78 : return IsOwnedByEntityHelper(entity, target, "IsMutualAlly");
231 : }
232 :
233 : function IsOwnedByEntityHelper(entity, target, check)
234 : {
235 : // Figure out which player controls us
236 78 : let owner = 0;
237 78 : let cmpOwnership = Engine.QueryInterface(entity, IID_Ownership);
238 78 : if (cmpOwnership)
239 78 : owner = cmpOwnership.GetOwner();
240 :
241 : // Figure out which player controls the target entity
242 78 : let targetOwner = 0;
243 78 : let cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
244 78 : if (cmpOwnershipTarget)
245 78 : targetOwner = cmpOwnershipTarget.GetOwner();
246 :
247 78 : let cmpPlayer = QueryPlayerIDInterface(owner);
248 :
249 78 : return cmpPlayer && cmpPlayer[check](targetOwner);
250 : }
251 :
252 : /**
253 : * Returns true if the entity 'target' is owned by player
254 : */
255 : function IsOwnedByPlayer(player, target)
256 : {
257 0 : var cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
258 0 : return cmpOwnershipTarget && player == cmpOwnershipTarget.GetOwner();
259 : }
260 :
261 : function IsOwnedByGaia(target)
262 : {
263 0 : return IsOwnedByPlayer(0, target);
264 : }
265 :
266 : /**
267 : * Returns true if the entity 'target' is owned by an ally of player
268 : */
269 : function IsOwnedByAllyOfPlayer(player, target)
270 : {
271 23 : return IsOwnedByHelper(player, target, "IsAlly");
272 : }
273 :
274 : function IsOwnedByMutualAllyOfPlayer(player, target)
275 : {
276 0 : return IsOwnedByHelper(player, target, "IsMutualAlly");
277 : }
278 :
279 : function IsOwnedByNeutralOfPlayer(player, target)
280 : {
281 0 : return IsOwnedByHelper(player, target, "IsNeutral");
282 : }
283 :
284 : function IsOwnedByEnemyOfPlayer(player, target)
285 : {
286 0 : return IsOwnedByHelper(player, target, "IsEnemy");
287 : }
288 :
289 : function IsOwnedByHelper(player, target, check)
290 : {
291 23 : let targetOwner = 0;
292 23 : let cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
293 23 : if (cmpOwnershipTarget)
294 23 : targetOwner = cmpOwnershipTarget.GetOwner();
295 :
296 23 : let cmpPlayer = QueryPlayerIDInterface(player);
297 :
298 23 : return cmpPlayer && cmpPlayer[check](targetOwner);
299 : }
300 :
301 36 : Engine.RegisterGlobal("LoadPlayerSettings", LoadPlayerSettings);
302 36 : Engine.RegisterGlobal("QueryOwnerEntityID", QueryOwnerEntityID);
303 36 : Engine.RegisterGlobal("QueryOwnerInterface", QueryOwnerInterface);
304 36 : Engine.RegisterGlobal("QueryPlayerIDInterface", QueryPlayerIDInterface);
305 36 : Engine.RegisterGlobal("QueryMiragedInterface", QueryMiragedInterface);
306 36 : Engine.RegisterGlobal("QueryBuilderListInterface", QueryBuilderListInterface);
307 36 : Engine.RegisterGlobal("IsOwnedByAllyOfEntity", IsOwnedByAllyOfEntity);
308 36 : Engine.RegisterGlobal("IsOwnedByMutualAllyOfEntity", IsOwnedByMutualAllyOfEntity);
309 36 : Engine.RegisterGlobal("IsOwnedByPlayer", IsOwnedByPlayer);
310 36 : Engine.RegisterGlobal("IsOwnedByGaia", IsOwnedByGaia);
311 36 : Engine.RegisterGlobal("IsOwnedByAllyOfPlayer", IsOwnedByAllyOfPlayer);
312 36 : Engine.RegisterGlobal("IsOwnedByMutualAllyOfPlayer", IsOwnedByMutualAllyOfPlayer);
313 36 : Engine.RegisterGlobal("IsOwnedByNeutralOfPlayer", IsOwnedByNeutralOfPlayer);
314 36 : Engine.RegisterGlobal("IsOwnedByEnemyOfPlayer", IsOwnedByEnemyOfPlayer);
|