Line data Source code
1 0 : var API3 = function(m)
2 : {
3 :
4 0 : m.EntityCollection = function(sharedAI, entities = new Map(), filters = [])
5 : {
6 0 : this._ai = sharedAI;
7 0 : this._entities = entities;
8 0 : this._filters = filters;
9 0 : this.dynamicProp = [];
10 0 : for (let filter of this._filters)
11 0 : if (filter.dynamicProperties.length)
12 0 : this.dynamicProp = this.dynamicProp.concat(filter.dynamicProperties);
13 :
14 0 : Object.defineProperty(this, "length", { "get": () => this._entities.size });
15 0 : this.frozen = false;
16 : };
17 :
18 0 : m.EntityCollection.prototype.Serialize = function()
19 : {
20 0 : let filters = [];
21 0 : for (let f of this._filters)
22 0 : filters.push(uneval(f));
23 0 : return {
24 : "ents": this.toIdArray(),
25 : "frozen": this.frozen,
26 : "filters": filters
27 : };
28 : };
29 :
30 0 : m.EntityCollection.prototype.Deserialize = function(data, sharedAI)
31 : {
32 0 : this._ai = sharedAI;
33 0 : for (let id of data.ents)
34 0 : this._entities.set(id, sharedAI._entities.get(id));
35 :
36 0 : for (let f of data.filters)
37 0 : this._filters.push(eval(f));
38 :
39 0 : if (data.frozen)
40 0 : this.freeze();
41 : else
42 0 : this.defreeze();
43 : };
44 :
45 : /**
46 : * If an entitycollection is frozen, it will never automatically add a unit.
47 : * But can remove one.
48 : * this makes it easy to create entity collection that will auto-remove dead units
49 : * but never add new ones.
50 : */
51 0 : m.EntityCollection.prototype.freeze = function()
52 : {
53 0 : this.frozen = true;
54 : };
55 :
56 0 : m.EntityCollection.prototype.defreeze = function()
57 : {
58 0 : this.frozen = false;
59 : };
60 :
61 0 : m.EntityCollection.prototype.toIdArray = function()
62 : {
63 0 : return Array.from(this._entities.keys());
64 : };
65 :
66 0 : m.EntityCollection.prototype.toEntityArray = function()
67 : {
68 0 : return Array.from(this._entities.values());
69 : };
70 :
71 0 : m.EntityCollection.prototype.values = function()
72 : {
73 0 : return this._entities.values();
74 : };
75 :
76 0 : m.EntityCollection.prototype.toString = function()
77 : {
78 0 : return "[EntityCollection " + this.toEntityArray().join(" ") + "]";
79 : };
80 :
81 0 : m.EntityCollection.prototype.filter = function(filter, thisp)
82 : {
83 0 : if (typeof filter == "function")
84 0 : filter = { "func": filter, "dynamicProperties": [] };
85 :
86 0 : let ret = new Map();
87 0 : for (let [id, ent] of this._entities)
88 0 : if (filter.func.call(thisp, ent, id, this))
89 0 : ret.set(id, ent);
90 :
91 0 : return new m.EntityCollection(this._ai, ret, this._filters.concat([filter]));
92 : };
93 :
94 : /**
95 : * Returns the (at most) n entities nearest to targetPos.
96 : */
97 0 : m.EntityCollection.prototype.filterNearest = function(targetPos, n)
98 : {
99 : // Compute the distance of each entity
100 0 : let data = []; // [ [id, ent, distance], ... ]
101 0 : for (let [id, ent] of this._entities)
102 0 : if (ent.position())
103 0 : data.push([id, ent, m.SquareVectorDistance(targetPos, ent.position())]);
104 :
105 : // Sort by increasing distance
106 0 : data.sort((a, b) => a[2] - b[2]);
107 :
108 0 : if (n === undefined)
109 0 : n = data.length;
110 : else
111 0 : n = Math.min(n, data.length);
112 :
113 : // Extract the first n
114 0 : let ret = new Map();
115 0 : for (let i = 0; i < n; ++i)
116 0 : ret.set(data[i][0], data[i][1]);
117 :
118 0 : return new m.EntityCollection(this._ai, ret);
119 : };
120 :
121 0 : m.EntityCollection.prototype.filter_raw = function(callback, thisp)
122 : {
123 0 : let ret = new Map();
124 0 : for (let [id, ent] of this._entities)
125 : {
126 0 : let val = ent._entity;
127 0 : if (callback.call(thisp, val, id, this))
128 0 : ret.set(id, ent);
129 : }
130 0 : return new m.EntityCollection(this._ai, ret);
131 : };
132 :
133 0 : m.EntityCollection.prototype.forEach = function(callback)
134 : {
135 0 : for (let ent of this._entities.values())
136 0 : callback(ent);
137 0 : return this;
138 : };
139 :
140 0 : m.EntityCollection.prototype.hasEntities = function()
141 : {
142 0 : return this._entities.size !== 0;
143 : };
144 :
145 0 : m.EntityCollection.prototype.move = function(x, z, queued = false, pushFront = false)
146 : {
147 0 : Engine.PostCommand(PlayerID, {
148 : "type": "walk",
149 : "entities": this.toIdArray(),
150 : "x": x,
151 : "z": z,
152 : "queued": queued,
153 : "pushFront": pushFront
154 : });
155 0 : return this;
156 : };
157 :
158 0 : m.EntityCollection.prototype.moveToRange = function(x, z, min, max, queued = false, pushFront = false)
159 : {
160 0 : Engine.PostCommand(PlayerID, {
161 : "type": "walk-to-range",
162 : "entities": this.toIdArray(),
163 : "x": x,
164 : "z": z,
165 : "min": min,
166 : "max": max,
167 : "queued": queued,
168 : "pushFront": pushFront
169 : });
170 0 : return this;
171 : };
172 :
173 0 : m.EntityCollection.prototype.attackMove = function(x, z, targetClasses, allowCapture = true, queued = false, pushFront = false)
174 : {
175 0 : Engine.PostCommand(PlayerID, {
176 : "type": "attack-walk",
177 : "entities": this.toIdArray(),
178 : "x": x,
179 : "z": z,
180 : "targetClasses": targetClasses,
181 : "allowCapture": allowCapture,
182 : "queued": queued,
183 : "pushFront": pushFront
184 : });
185 0 : return this;
186 : };
187 :
188 0 : m.EntityCollection.prototype.moveIndiv = function(x, z, queued = false, pushFront = false)
189 : {
190 0 : for (let id of this._entities.keys())
191 0 : Engine.PostCommand(PlayerID, {
192 : "type": "walk",
193 : "entities": [id],
194 : "x": x,
195 : "z": z,
196 : "queued": queued,
197 : "pushFront": pushFront
198 : });
199 0 : return this;
200 : };
201 :
202 0 : m.EntityCollection.prototype.garrison = function(target, queued = false, pushFront = false)
203 : {
204 0 : Engine.PostCommand(PlayerID, {
205 : "type": "garrison",
206 : "entities": this.toIdArray(),
207 : "target": target.id(),
208 : "queued": queued,
209 : "pushFront": pushFront
210 : });
211 0 : return this;
212 : };
213 :
214 0 : m.EntityCollection.prototype.occupyTurret = function(target, queued = false, pushFront = false)
215 : {
216 0 : Engine.PostCommand(PlayerID, {
217 : "type": "occupy-turret",
218 : "entities": this.toIdArray(),
219 : "target": target.id(),
220 : "queued": queued,
221 : "pushFront": pushFront
222 : });
223 0 : return this;
224 : };
225 :
226 0 : m.EntityCollection.prototype.destroy = function()
227 : {
228 0 : Engine.PostCommand(PlayerID, { "type": "delete-entities", "entities": this.toIdArray() });
229 0 : return this;
230 : };
231 :
232 0 : m.EntityCollection.prototype.attack = function(unitId, queued = false, pushFront = false)
233 : {
234 0 : Engine.PostCommand(PlayerID, {
235 : "type": "attack",
236 : "entities": this.toIdArray(),
237 : "target": unitId,
238 : "queued": queued,
239 : "pushFront": pushFront
240 : });
241 0 : return this;
242 : };
243 :
244 : /** violent, aggressive, defensive, passive, standground */
245 0 : m.EntityCollection.prototype.setStance = function(stance)
246 : {
247 0 : Engine.PostCommand(PlayerID, {
248 : "type": "stance",
249 : "entities": this.toIdArray(),
250 : "name": stance
251 : });
252 0 : return this;
253 : };
254 :
255 : /** Returns the average position of all units */
256 0 : m.EntityCollection.prototype.getCentrePosition = function()
257 : {
258 0 : let sumPos = [0, 0];
259 0 : let count = 0;
260 0 : for (let ent of this._entities.values())
261 : {
262 0 : if (!ent.position())
263 0 : continue;
264 0 : sumPos[0] += ent.position()[0];
265 0 : sumPos[1] += ent.position()[1];
266 0 : count++;
267 : }
268 :
269 0 : return count ? [sumPos[0]/count, sumPos[1]/count] : undefined;
270 : };
271 :
272 : /**
273 : * returns the average position from the sample first units.
274 : * This might be faster for huge collections, but there's
275 : * always a risk that it'll be unprecise.
276 : */
277 0 : m.EntityCollection.prototype.getApproximatePosition = function(sample)
278 : {
279 0 : let sumPos = [0, 0];
280 0 : let i = 0;
281 0 : for (let ent of this._entities.values())
282 : {
283 0 : if (!ent.position())
284 0 : continue;
285 0 : sumPos[0] += ent.position()[0];
286 0 : sumPos[1] += ent.position()[1];
287 0 : i++;
288 0 : if (i === sample)
289 0 : break;
290 : }
291 :
292 0 : return i ? [sumPos[0]/i, sumPos[1]/i] : undefined;
293 : };
294 :
295 0 : m.EntityCollection.prototype.hasEntId = function(id)
296 : {
297 0 : return this._entities.has(id);
298 : };
299 :
300 : /** Removes an entity from the collection, returns true if the entity was a member, false otherwise */
301 0 : m.EntityCollection.prototype.removeEnt = function(ent)
302 : {
303 0 : if (!this._entities.has(ent.id()))
304 0 : return false;
305 0 : this._entities.delete(ent.id());
306 0 : return true;
307 : };
308 :
309 : /** Adds an entity to the collection, returns true if the entity was not member, false otherwise */
310 0 : m.EntityCollection.prototype.addEnt = function(ent)
311 : {
312 0 : if (this._entities.has(ent.id()))
313 0 : return false;
314 0 : this._entities.set(ent.id(), ent);
315 0 : return true;
316 : };
317 :
318 : /**
319 : * Checks the entity against the filters, and adds or removes it appropriately, returns true if the
320 : * entity collection was modified.
321 : * Force can add a unit despite a freezing.
322 : * If an entitycollection is frozen, it will never automatically add a unit.
323 : * But can remove one.
324 : */
325 0 : m.EntityCollection.prototype.updateEnt = function(ent, force)
326 : {
327 0 : let passesFilters = true;
328 0 : for (let filter of this._filters)
329 0 : passesFilters = passesFilters && filter.func(ent);
330 :
331 0 : if (passesFilters)
332 : {
333 0 : if (!force && this.frozen)
334 0 : return false;
335 0 : return this.addEnt(ent);
336 : }
337 :
338 0 : return this.removeEnt(ent);
339 : };
340 :
341 0 : m.EntityCollection.prototype.registerUpdates = function()
342 : {
343 0 : this._ai.registerUpdatingEntityCollection(this);
344 : };
345 :
346 0 : m.EntityCollection.prototype.unregister = function()
347 : {
348 0 : this._ai.removeUpdatingEntityCollection(this);
349 : };
350 :
351 0 : m.EntityCollection.prototype.dynamicProperties = function()
352 : {
353 0 : return this.dynamicProp;
354 : };
355 :
356 0 : m.EntityCollection.prototype.setUID = function(id)
357 : {
358 0 : this._UID = id;
359 : };
360 :
361 0 : m.EntityCollection.prototype.getUID = function()
362 : {
363 0 : return this._UID;
364 : };
365 :
366 0 : return m;
367 :
368 : }(API3);
|