~harrison-rt/+junk/jaguar_company

« back to all changes in this revision

Viewing changes to tags/2.1/jaguar_company_2.1.oxp/Scripts/jaguar_company_patrol.js

  • Committer: Richard Harrison
  • Date: 2013-01-19 22:57:39 UTC
  • Revision ID: harrison.rt@gmail.com-20130119225739-8f9knzzag8xd7zhm
Tags: 2.2
* Wrong variable in the buoy script.
* Corrected a logic check in the asteroid script.
* Optimized the cleanup code in jaguar_company_attackers.js
* Fewer boulders.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*jslint indent: 4, maxlen: 120, maxerr: 50, white: true, es5: true, undef: true, regexp: true, newcap: true */
 
2
/*jshint es5: true, undef: true, eqnull: true, noempty: true, eqeqeq: true, boss: true, loopfunc: true, laxbreak: true,
 
3
strict: true, curly: true */
 
4
/*global system, log, worldScripts, Timer */
 
5
 
 
6
/* Jaguar Company Patrol
 
7
 *
 
8
 * Copyright © 2012 Richard Thomas Harrison (Tricky)
 
9
 *
 
10
 * This work is licensed under the Creative Commons
 
11
 * Attribution-Noncommercial-Share Alike 3.0 Unported License.
 
12
 *
 
13
 * To view a copy of this license, visit
 
14
 * http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter
 
15
 * to Creative Commons, 171 Second Street, Suite 300, San Francisco,
 
16
 * California, 94105, USA.
 
17
 *
 
18
 * Ship related functions for the patrol and intercept AIs.
 
19
 * Missile subentity code based on tgGeneric_externalMissiles.js by Thargoid (modified)
 
20
 */
 
21
 
 
22
(function () {
 
23
    "use strict";
 
24
 
 
25
    /* Standard public variables for OXP scripts. */
 
26
    this.name = "jaguar_company_patrol.js";
 
27
    this.author = "Tricky";
 
28
    this.copyright = "© 2012 Richard Thomas Harrison (Tricky)";
 
29
    this.license = "CC BY-NC-SA 3.0";
 
30
    this.description = "Ship script for the Jaguar Company Patrol ships.";
 
31
    this.version = "1.8";
 
32
 
 
33
    /* Private variable. */
 
34
    var p_patrol = {};
 
35
 
 
36
    /* Ship event callbacks. */
 
37
 
 
38
    /* Initialise various variables on ship birth. */
 
39
    this.shipSpawned = function () {
 
40
        var counter;
 
41
 
 
42
        /* No longer needed after setting up. */
 
43
        delete this.shipSpawned;
 
44
 
 
45
        /* Initialise the p_patrol variable object.
 
46
         * Encapsulates all private global data.
 
47
         */
 
48
        p_patrol = {
 
49
            /* Cache the world scripts. */
 
50
            mainScript : worldScripts["Jaguar Company"],
 
51
            attackersScript : worldScripts["Jaguar Company Attackers"],
 
52
            /* Local copies of the logging variables. */
 
53
            logging : worldScripts["Jaguar Company"].$logging,
 
54
            logExtra : worldScripts["Jaguar Company"].$logExtra,
 
55
            /* Local copy of the friendRoles array. */
 
56
            friendRoles : worldScripts["Jaguar Company Attackers"].$friendRoles,
 
57
            /* Standard distances. */
 
58
            distance : {
 
59
                close : 10000,
 
60
                nearby : 20000,
 
61
                farAway : 40000
 
62
            },
 
63
            /* Default missile. */
 
64
            missileRole : "EQ_HARDENED_MISSILE",
 
65
            /* Default number of missiles. */
 
66
            initialMissiles : this.ship.missileCapacity,
 
67
            /* Starting amount of fuel. */
 
68
            fuel : this.ship.fuel
 
69
        };
 
70
 
 
71
        /* Register this ship as a friendly. */
 
72
        p_patrol.attackersScript.$addFriendly(this.ship);
 
73
        /* Get a unique name for the patrol ship. */
 
74
        this.ship.displayName = p_patrol.mainScript.$uniqueShipName(this.ship.name);
 
75
        /* Increase the number of patrol ships in the system. */
 
76
        p_patrol.mainScript.$numPatrolShips += 1;
 
77
        /* Timer reference. */
 
78
        this.$addFuelTimerReference = new Timer(this, this.$addFuelTimer, 1, 1);
 
79
 
 
80
        /* Thargoid's missile code. */
 
81
        /* Just to ensure ship is fully loaded with selected missile type and nothing else. */
 
82
        if (this.ship.scriptInfo.missileRole) {
 
83
            /* missileRole should be defined in shipdata.plist */
 
84
            p_patrol.missileRole = this.ship.scriptInfo.missileRole;
 
85
        }
 
86
 
 
87
        if (this.ship.scriptInfo.initialMissiles) {
 
88
            p_patrol.initialMissiles = parseInt(this.ship.scriptInfo.initialMissiles, 10);
 
89
        }
 
90
 
 
91
        if (this.ship.missiles.length > 0) {
 
92
            /* Remove all spawning missiles. */
 
93
            this.ship.awardEquipment("EQ_MISSILE_REMOVAL");
 
94
        }
 
95
 
 
96
        /* Restock with selected ones. */
 
97
        for (counter = 0; counter < p_patrol.initialMissiles; counter += 1) {
 
98
            this.ship.awardEquipment(p_patrol.missileRole);
 
99
        }
 
100
    };
 
101
 
 
102
    /* Thargoid's missile code. (Simplified - taken out the local function.)
 
103
     *
 
104
     * INPUT
 
105
     *   missile - missile entity.
 
106
     */
 
107
    this.shipFiredMissile = function (missile) {
 
108
        var counter,
 
109
        subEntities,
 
110
        subEntity;
 
111
 
 
112
        subEntities = this.ship.subEntities;
 
113
 
 
114
        if (!subEntities || !subEntities.length) {
 
115
            /* If we've run out of sub-ents before we run out of missiles. */
 
116
            return;
 
117
        }
 
118
 
 
119
        /* Set counter to number of sub-ents minus 1 (as entity array goes up from zero). */
 
120
        for (counter = subEntities.length - 1; counter >= 0; counter -= 1) {
 
121
            subEntity = subEntities[counter];
 
122
 
 
123
            if (subEntity.hasRole(missile.primaryRole)) {
 
124
                /* If the sub-ent is the same as the missile being fired. */
 
125
                /* Move the fired missile to the sub-ent position and convert to real-world co-ordinates. */
 
126
                missile.position = this.ship.position.add(subEntity.position.rotateBy(this.ship.orientation));
 
127
                /* Point the missile in the right direction. */
 
128
                missile.orientation = subEntity.orientation.multiply(this.ship.orientation);
 
129
                /* Desired speed of missile is it's maximum speed. */
 
130
                missile.desiredSpeed = missile.maxSpeed;
 
131
                /* Remove the sub-ent version of the missile. */
 
132
                subEntity.remove();
 
133
 
 
134
                /* Come out of the loop, as we've done our swap. */
 
135
                break;
 
136
            }
 
137
        }
 
138
    };
 
139
 
 
140
    /* Patrol ship was removed by script. */
 
141
    this.shipRemoved = function (suppressDeathEvent) {
 
142
        if (suppressDeathEvent) {
 
143
            return;
 
144
        }
 
145
 
 
146
        /* Decrease the number of patrol ships in the system. */
 
147
        worldScripts["Jaguar Company"].$numPatrolShips -= 1;
 
148
    };
 
149
 
 
150
    /* The patrol ship has just become invalid. */
 
151
    this.entityDestroyed = function () {
 
152
        /* Decrease the number of patrol ships in the system. */
 
153
        worldScripts["Jaguar Company"].$numPatrolShips -= 1;
 
154
        /* Stop and remove the timer. */
 
155
        this.$removeAddFuelTimer();
 
156
    };
 
157
 
 
158
    /* Taking damage. Check attacker and what type.
 
159
     *
 
160
     * INPUTS
 
161
     *   amount - amount of damage.
 
162
     *   attacker - entity that caused the damage.
 
163
     *   type - type of damage as a string.
 
164
     */
 
165
    this.shipTakingDamage = function (amount, attacker, type) {
 
166
        if (!attacker || !attacker.isValid || !attacker.isShip) {
 
167
            /* If it isn't a ship dealing damage then carry on with the damage. */
 
168
            return;
 
169
        }
 
170
 
 
171
        if (p_patrol.friendRoles.indexOf(attacker.entityPersonality) > -1 && type === "scrape damage") {
 
172
            /* Cancel damage from collision with Jaguar Company ships. */
 
173
            this.ship.energy += amount;
 
174
 
 
175
            /* Target the ship we are colliding with. */
 
176
            this.ship.target = attacker;
 
177
 
 
178
            if (this.ship.AI === "jaguar_company_interceptAI.plist") {
 
179
                /* Force an exit of the intercept AI. */
 
180
                this.ship.lightsActive = false;
 
181
                this.ship.exitAI();
 
182
            }
 
183
 
 
184
            /* Move away from the ship we are colliding with. */
 
185
            this.ship.reactToAIMessage("JAGUAR_COMPANY_TOO_CLOSE");
 
186
        }
 
187
    };
 
188
 
 
189
    /* Stop and remove the timer. */
 
190
    this.$removeAddFuelTimer = function () {
 
191
        if (this.$addFuelTimerReference) {
 
192
            if (this.$addFuelTimerReference.isRunning) {
 
193
                this.$addFuelTimerReference.stop();
 
194
            }
 
195
 
 
196
            delete this.$addFuelTimerReference;
 
197
        }
 
198
    };
 
199
 
 
200
    /* addFuel in the AI doesn't allow small increases.
 
201
     *
 
202
     * This function allow us to increment the amount of fuel in tinier amounts.
 
203
     * Called every second.
 
204
     */
 
205
    this.$addFuelTimer = function () {
 
206
        var actualFuel,
 
207
        internalFuel;
 
208
 
 
209
        if (this.ship.speed > this.ship.maxSpeed) {
 
210
            /* No fuel collection during Injection or Torus drive. */
 
211
            return;
 
212
        }
 
213
 
 
214
        /* Round off the actual fuel amount to the nearest lowest tenth.
 
215
         * The actual fuel amount can be something like 6.6000000000000005 even though
 
216
         * the system just uses the 1st decimal place.
 
217
         */
 
218
        actualFuel = Math.floor(this.ship.fuel * 10) / 10;
 
219
        /* The internal fuel amount is also rounded off in a similar manner for the following adjustment. */
 
220
        internalFuel = Math.floor(p_patrol.fuel * 10) / 10;
 
221
 
 
222
        /* Adjust the internal fuel amount if the actual fuel amount has changed.
 
223
         * Needed if the actual fuel amount has been reduced by Injection or Torus drive.
 
224
         */
 
225
        if (actualFuel !== internalFuel) {
 
226
            p_patrol.fuel = actualFuel;
 
227
        }
 
228
 
 
229
        if (p_patrol.fuel < 7) {
 
230
            /* 0.1 LY of fuel every 100 seconds. */
 
231
            p_patrol.fuel += 0.001;
 
232
 
 
233
            /* Cap the fuel level. */
 
234
            if (p_patrol.fuel > 7) {
 
235
                p_patrol.fuel = 7;
 
236
            }
 
237
 
 
238
            /* Set the actual fuel amount to the new fuel amount.
 
239
             * Adjust to the nearest lowest tenth.
 
240
             */
 
241
            this.ship.fuel = Math.floor(p_patrol.fuel * 10) / 10;
 
242
        } else {
 
243
            /* Make sure that the fuel tanks aren't over filled. */
 
244
            p_patrol.fuel = 7;
 
245
            this.ship.fuel = 7;
 
246
        }
 
247
    };
 
248
 
 
249
    /* Find the average distance to all the other ships.
 
250
     *
 
251
     * INPUT
 
252
     *   otherShips - array of ships.
 
253
     *
 
254
     * RESULT
 
255
     *   result - average distance to all the other ships.
 
256
     */
 
257
    this.$queryAverageDistance = function (otherShips) {
 
258
        var averageDistance = 0,
 
259
        otherShipsLength,
 
260
        otherShipsCounter,
 
261
        otherShip,
 
262
        distance;
 
263
 
 
264
        if (!otherShips.length) {
 
265
            return 0;
 
266
        }
 
267
 
 
268
        /* Cache the length. */
 
269
        otherShipsLength = otherShips.length;
 
270
 
 
271
        for (otherShipsCounter = 0; otherShipsCounter < otherShipsLength; otherShipsCounter += 1) {
 
272
            otherShip = otherShips[otherShipsCounter];
 
273
            /* Centre to centre distance. */
 
274
            distance = this.ship.position.distanceTo(otherShip.position);
 
275
            /* Take off the collision radius of this ship. */
 
276
            distance -= this.ship.collisionRadius;
 
277
            /* Take off the collision radius of the other ship. */
 
278
            distance -= otherShip.collisionRadius;
 
279
            /* Add this distance to all the other distances. */
 
280
            averageDistance += distance;
 
281
        }
 
282
 
 
283
        /* Average all the distances and return it. */
 
284
        return (averageDistance /= otherShipsLength);
 
285
    };
 
286
 
 
287
    /* Set the co-ordinates to the surface of the entity.
 
288
     * This borrows some code from 'src/Core/Entities/ShipEntityAI.m - setCourseToPlanet'
 
289
     *
 
290
     * INPUT
 
291
     *   entity - entity to set co-ordinates to.
 
292
     */
 
293
    this.$setCoordsToEntity = function (entity) {
 
294
        var position = entity.position,
 
295
        distance,
 
296
        ratio,
 
297
        variation;
 
298
 
 
299
        /* Calculate a vector position between the entity's surface and the ship. */
 
300
        distance = this.ship.position.distanceTo(position);
 
301
        ratio = (entity.collisionRadius + this.ship.collisionRadius + 100) / distance;
 
302
        position = Vector3D.interpolate(position, this.ship.position, ratio);
 
303
 
 
304
        /* Higher variation if further away. */
 
305
        variation = (distance > 51200 ? 0.5 : 0.2);
 
306
 
 
307
        /* Move the vector a random amount. */
 
308
        position.x += variation * (Math.random() - variation);
 
309
        position.y += variation * (Math.random() - variation);
 
310
        position.z += variation * (Math.random() - variation);
 
311
 
 
312
        /* Save this position for 'setDestinationFromCoordinates' in the AI. */
 
313
        this.ship.savedCoordinates = position;
 
314
    };
 
315
 
 
316
    /* AI functions. */
 
317
 
 
318
    /* Save the current AI state. */
 
319
    this.$saveAIState = function () {
 
320
        p_patrol.saveAIState = this.ship.AIState;
 
321
    };
 
322
 
 
323
    /* Recall the saved AI state. */
 
324
    this.$recallAIState = function () {
 
325
        this.ship.AIState = p_patrol.saveAIState;
 
326
    };
 
327
 
 
328
    /* Set the co-ordinates to the surface of the main planet. */
 
329
    this.$setCoordsToMainPlanet = function () {
 
330
        this.$setCoordsToEntity(system.mainPlanet);
 
331
    };
 
332
 
 
333
    /* Set the co-ordinates to the fake interstellar witchpoint buoy. */
 
334
    this.$setCoordsToInterstellarWitchpoint = function () {
 
335
        this.$setCoordsToEntity(p_patrol.mainScript.$witchpointBuoy);
 
336
    };
 
337
 
 
338
    /* Set the co-ordinates to the surface of the witchpoint buoy. */
 
339
    this.$setCoordsToWitchpoint = function () {
 
340
        var witchpointBuoy = p_patrol.mainScript.$witchpointBuoy;
 
341
 
 
342
        if (!witchpointBuoy || !witchpointBuoy.isValid) {
 
343
            /* No witchpoint buoy. Patrol the base to the planet lane. */
 
344
            p_patrol.mainScript.$initRoute("BP");
 
345
            this.ship.reactToAIMessage("JAGUAR_COMPANY_WITCHPOINT_NOT_FOUND");
 
346
        } else {
 
347
            this.$setCoordsToEntity(p_patrol.mainScript.$witchpointBuoy);
 
348
            this.ship.reactToAIMessage("JAGUAR_COMPANY_WITCHPOINT_FOUND");
 
349
        }
 
350
    };
 
351
 
 
352
    /* Set the co-ordinates to the surface of the base. */
 
353
    this.$setCoordsToJaguarCompanyBase = function () {
 
354
        var base = p_patrol.mainScript.$jaguarCompanyBase;
 
355
 
 
356
        if (!base || !base.isValid) {
 
357
            if (system.isInterstellarSpace) {
 
358
                this.ship.fuel = 7;
 
359
                this.ship.reactToAIMessage("JAGUAR_COMPANY_EXIT_INTERSTELLAR");
 
360
            } else {
 
361
                /* If it has gone, just patrol the witchpoint to the planet lane. */
 
362
                p_patrol.mainScript.$initRoute("WP");
 
363
                this.ship.reactToAIMessage("JAGUAR_COMPANY_BASE_NOT_FOUND");
 
364
            }
 
365
        } else {
 
366
            if (p_patrol.mainScript.$buoy && p_patrol.mainScript.$buoy.isValid) {
 
367
                /* Set the coords to the buoy. */
 
368
                this.$setCoordsToEntity(p_patrol.mainScript.$buoy);
 
369
            } else {
 
370
                /* Set the coords to the base. */
 
371
                this.$setCoordsToEntity(base);
 
372
            }
 
373
 
 
374
            this.ship.reactToAIMessage("JAGUAR_COMPANY_BASE_FOUND");
 
375
        }
 
376
    };
 
377
 
 
378
    /* Jaguar Company were forced out of interstellar space as there was no base.
 
379
     * Create a new base in the new system.
 
380
     */
 
381
    this.$addPatrolToNewSystem = function () {
 
382
        if (system.shipsWithPrimaryRole("jaguar_company_patrol").length === p_patrol.mainScript.$numPatrolShips) {
 
383
            /* Last ship out will create the base. */
 
384
            if (!p_patrol.mainScript.$setUpCompany()) {
 
385
                /* Base would not be created, just patrol the witchpoint to the planet lane. */
 
386
                p_patrol.mainScript.$initRoute("WP");
 
387
            } else {
 
388
                /* Base was created. Set the route. Should be a route to the base. */
 
389
                p_patrol.mainScript.$changeRoute(-1);
 
390
            }
 
391
        }
 
392
    };
 
393
 
 
394
    /* Check to see if the patrol ship is the initiator of the wormhole or is following. */
 
395
    this.$checkHyperspaceFollow = function () {
 
396
        if (p_patrol.mainScript.$hyperspaceFollow) {
 
397
            /* This ship is following. */
 
398
            this.ship.savedCoordinates = p_patrol.mainScript.$hyperspaceFollow;
 
399
            this.ship.reactToAIMessage("JAGUAR_COMPANY_HYPERSPACE_FOLLOW");
 
400
 
 
401
            return;
 
402
        }
 
403
 
 
404
        /* This ship is opening the initial wormhole. */
 
405
        p_patrol.mainScript.$hyperspaceFollow = this.ship.position;
 
406
        this.ship.reactToAIMessage("JAGUAR_COMPANY_HYPERSPACE");
 
407
    };
 
408
 
 
409
    /* Check current patrol route. */
 
410
    this.$checkRoute = function () {
 
411
        /* Call common code used by all of Jaguar Company. */
 
412
        p_patrol.mainScript.$checkRoute(this.ship);
 
413
    };
 
414
 
 
415
    /* Finished the current patrol route, change to the next one. */
 
416
    this.$finishedRoute = function () {
 
417
        /* Call common code used by all of Jaguar Company. */
 
418
        p_patrol.mainScript.$finishedRoute(this.ship, "jaguar_company_patrol", "JAGUAR_COMPANY_REGROUP");
 
419
    };
 
420
 
 
421
    /* Scan for the other ships to see if the full group is present. */
 
422
    this.$scanForAllJaguarCompany = function () {
 
423
        var base,
 
424
        patrolShips,
 
425
        counter,
 
426
        length,
 
427
        lurkPosition,
 
428
        variation;
 
429
 
 
430
        if (p_patrol.mainScript.$maxPatrolShips === 1) {
 
431
            /* We are on our own. */
 
432
            this.ship.reactToAIMessage("JAGUAR_COMPANY_NOT_FOUND");
 
433
 
 
434
            return;
 
435
        }
 
436
 
 
437
        patrolShips = system.shipsWithPrimaryRole("jaguar_company_patrol");
 
438
 
 
439
        if (patrolShips.length === p_patrol.mainScript.$numPatrolShips ||
 
440
            p_patrol.mainScript.$patrolShipsFullyLaunched) {
 
441
            /* Announce that we have found all of Jaguar Company to the AI. */
 
442
            this.ship.reactToAIMessage("JAGUAR_COMPANY_ALL_PRESENT");
 
443
        } else {
 
444
            base = system.shipsWithRole("jaguar_company_base");
 
445
 
 
446
            if (base.length > 0) {
 
447
                /* There can only really be 1 base. */
 
448
                lurkPosition = base[0].position;
 
449
            } else {
 
450
                /* START OF CODE THAT SHOULD NEVER BE REACHED.
 
451
                 * This is here purely for error checking sake.
 
452
                 * If the base is destroyed it will set the patrol ships fully launched variable,
 
453
                 * therefore this code block shouldn't be reached.
 
454
                 */
 
455
                if (patrolShips.length === 1) {
 
456
                    /* We are on our own. */
 
457
                    lurkPosition = patrolShips[0].position;
 
458
                } else {
 
459
                    /* Cache the length. */
 
460
                    length = patrolShips.length;
 
461
 
 
462
                    /* Work out the midpoint position of all ships. */
 
463
                    lurkPosition = new Vector3D(0, 0, 0);
 
464
 
 
465
                    for (counter = 0; counter < length; counter += 1) {
 
466
                        lurkPosition = lurkPosition.add(patrolShips[counter].position);
 
467
                    }
 
468
 
 
469
                    lurkPosition.x /= length;
 
470
                    lurkPosition.y /= length;
 
471
                    lurkPosition.z /= length;
 
472
 
 
473
                    /* Higher variation if further away. */
 
474
                    variation = (this.ship.position.distanceTo(lurkPosition) > 51200 ? 0.5 : 0.2);
 
475
 
 
476
                    /* Move the vector a random amount. */
 
477
                    lurkPosition.x += variation * (Math.random() - variation);
 
478
                    lurkPosition.y += variation * (Math.random() - variation);
 
479
                    lurkPosition.z += variation * (Math.random() - variation);
 
480
                }
 
481
                /* END OF CODE THAT SHOULD NEVER BE REACHED. */
 
482
            }
 
483
 
 
484
            /* Move the lurk position 20km out in a random direction and save the co-ordinates for the AI. */
 
485
            this.ship.savedCoordinates = lurkPosition.add(Vector3D.randomDirection(20000));
 
486
            this.ship.reactToAIMessage("JAGUAR_COMPANY_NOT_PRESENT");
 
487
        }
 
488
    };
 
489
 
 
490
    /* Scan for the other ships and find the midpoint position of the group. */
 
491
    this.$scanForJaguarCompany = function () {
 
492
        var otherShips,
 
493
        otherShipsLength,
 
494
        otherShipsCounter,
 
495
        midpointPosition,
 
496
        variation;
 
497
 
 
498
        otherShips = system.shipsWithPrimaryRole("jaguar_company_patrol", this.ship);
 
499
 
 
500
        if (!otherShips.length) {
 
501
            /* We are on our own. */
 
502
            this.ship.reactToAIMessage("JAGUAR_COMPANY_NOT_FOUND");
 
503
 
 
504
            return;
 
505
        }
 
506
 
 
507
        /* Cache the length. */
 
508
        otherShipsLength = otherShips.length;
 
509
 
 
510
        /* Work out the midpoint position of all ships. */
 
511
        midpointPosition = this.ship.position;
 
512
 
 
513
        for (otherShipsCounter = 0; otherShipsCounter < otherShipsLength; otherShipsCounter += 1) {
 
514
            midpointPosition = midpointPosition.add(otherShips[otherShipsCounter].position);
 
515
        }
 
516
 
 
517
        midpointPosition.x /= (otherShipsLength + 1);
 
518
        midpointPosition.y /= (otherShipsLength + 1);
 
519
        midpointPosition.z /= (otherShipsLength + 1);
 
520
 
 
521
        /* Higher variation if further away. */
 
522
        variation = (this.ship.position.distanceTo(midpointPosition) > 51200 ? 0.5 : 0.2);
 
523
 
 
524
        /* Move the vector a random amount. */
 
525
        midpointPosition.x += variation * (Math.random() - variation);
 
526
        midpointPosition.y += variation * (Math.random() - variation);
 
527
        midpointPosition.z += variation * (Math.random() - variation);
 
528
 
 
529
        /* Save the co-ordinates for the AI. */
 
530
        this.ship.savedCoordinates = midpointPosition;
 
531
        /* Announce that we have found Jaguar Company to the AI. */
 
532
        this.ship.reactToAIMessage("JAGUAR_COMPANY_FOUND");
 
533
    };
 
534
 
 
535
    /* Check how close we are to other ships.
 
536
     *
 
537
     * INPUT
 
538
     *   minimumDistance - closest distance allowed.
 
539
     */
 
540
    this.$checkJaguarCompanyClosestDistance = function (minimumDistance) {
 
541
        var actualDistance,
 
542
        otherShips;
 
543
 
 
544
        /* More ships will increase the minimum distance. */
 
545
        actualDistance = minimumDistance * Math.ceil(p_patrol.mainScript.$numPatrolShips / 8);
 
546
        /* Modify for surface to surface. */
 
547
        actualDistance += this.ship.collisionRadius;
 
548
        /* Check for any patrol ships within the calculated sphere. */
 
549
        otherShips = system.shipsWithPrimaryRole("jaguar_company_patrol", this.ship, actualDistance);
 
550
 
 
551
        if (!otherShips.length) {
 
552
            this.ship.reactToAIMessage("JAGUAR_COMPANY_DISTANCE_OK");
 
553
        } else {
 
554
            /* If we are less than the minimum distance from the closest ship then we need to move away. */
 
555
            this.ship.target = otherShips[0];
 
556
            this.ship.reactToAIMessage("JAGUAR_COMPANY_TOO_CLOSE");
 
557
        }
 
558
 
 
559
        return;
 
560
    };
 
561
 
 
562
    /* Check our average distance to all other ships. */
 
563
    this.$checkJaguarCompanyAverageDistance = function () {
 
564
        var otherShips,
 
565
        averageDistance,
 
566
        close,
 
567
        nearby,
 
568
        farAway;
 
569
 
 
570
        otherShips = system.shipsWithPrimaryRole("jaguar_company_patrol", this.ship);
 
571
 
 
572
        if (!otherShips.length) {
 
573
            /* Return immediately if we are on our own. */
 
574
            return;
 
575
        }
 
576
 
 
577
        /* Find the average distance to all the other ships. */
 
578
        averageDistance = this.$queryAverageDistance(otherShips);
 
579
 
 
580
        close = (p_patrol.distance.close) + ((Math.random() * 2000.0) - 1000.0);
 
581
        nearby = (p_patrol.distance.nearby) + ((Math.random() * 2000.0) - 1000.0);
 
582
        farAway = (p_patrol.distance.farAway) + ((Math.random() * 2000.0) - 1000.0);
 
583
 
 
584
        /* I would love to create a fuzzy logic controller for this. */
 
585
        if (averageDistance < close) {
 
586
            /* We have regrouped. */
 
587
            this.ship.sendAIMessage("JAGUAR_COMPANY_REGROUPED");
 
588
        } else if (averageDistance >= close && averageDistance < nearby) {
 
589
            /* We are close. */
 
590
            this.ship.reactToAIMessage("JAGUAR_COMPANY_CLOSE");
 
591
        } else if (averageDistance >= nearby && averageDistance < farAway) {
 
592
            /* We are nearby. */
 
593
            this.ship.reactToAIMessage("JAGUAR_COMPANY_NEARBY");
 
594
        } else {
 
595
            /* We are far away. */
 
596
            this.ship.reactToAIMessage("JAGUAR_COMPANY_FAR_AWAY");
 
597
        }
 
598
    };
 
599
 
 
600
    /* Tell everyone to regroup if the average distance to all the other ships is too great.
 
601
     *
 
602
     * INPUT
 
603
     *   maxDistance - furthest distance allowed before a regroup message is sent out.
 
604
     */
 
605
    this.$checkJaguarCompanyRegroup = function (maxDistance) {
 
606
        var otherShips,
 
607
        otherShipsLength,
 
608
        otherShipsCounter;
 
609
 
 
610
        otherShips = system.shipsWithPrimaryRole("jaguar_company_patrol", this.ship);
 
611
 
 
612
        if (!otherShips.length) {
 
613
            /* Return immediately if we are on our own. */
 
614
            return;
 
615
        }
 
616
 
 
617
        /* Find the average distance to all the other ships. */
 
618
        if (this.$queryAverageDistance(otherShips) >= maxDistance + ((Math.random() * 2000.0) - 1000.0)) {
 
619
            /* Tell all ships, including ourself, to regroup. */
 
620
            this.ship.reactToAIMessage("JAGUAR_COMPANY_REGROUP");
 
621
 
 
622
            /* Cache the length. */
 
623
            otherShipsLength = otherShips.length;
 
624
 
 
625
            for (otherShipsCounter = 0; otherShipsCounter < otherShipsLength; otherShipsCounter += 1) {
 
626
                otherShips[otherShipsCounter].reactToAIMessage("JAGUAR_COMPANY_REGROUP");
 
627
            }
 
628
        }
 
629
    };
 
630
}).call(this);