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, missionVariables, Timer */
8
* Copyright © 2012 Richard Thomas Harrison (Tricky)
10
* This work is licensed under the Creative Commons
11
* Attribution-Noncommercial-Share Alike 3.0 Unported License.
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.
18
* Ship related functions for the base AI.
24
/* Standard public variables for OXP scripts. */
25
this.name = "jaguar_company_base.js";
26
this.author = "Tricky";
27
this.copyright = "© 2012 Richard Thomas Harrison (Tricky)";
28
this.license = "CC BY-NC-SA 3.0";
29
this.description = "Ship script for the Jaguar Company Base.";
32
/* Private variable. */
35
/* Ship event callbacks. */
37
/* Initialise various variables on ship birth. */
38
this.shipSpawned = function () {
44
/* No longer needed after setting up. */
45
delete this.shipSpawned;
47
/* Initialise the p_base variable object.
48
* Encapsulates all private global data.
51
/* Cache the world scripts. */
52
mainScript : worldScripts["Jaguar Company"],
53
attackersScript : worldScripts["Jaguar Company Attackers"],
54
/* Local copies of the logging variables. */
55
logging : worldScripts["Jaguar Company"].$logging,
56
logExtra : worldScripts["Jaguar Company"].$logExtra
59
/* Register this base as a friendly. */
60
p_base.attackersScript.$addFriendly(this.ship);
62
if (p_base.mainScript.$swapBase) {
63
/* Swapping base roles. */
65
/* How many patrol ships have launched. */
66
p_base.patrolShipsLaunched = system.shipsWithPrimaryRole("jaguar_company_patrol").length;
67
/* Has the miner launched. */
68
p_base.minerLaunched = (system.shipsWithRole("jaguar_company_miner").length !== 0);
69
/* Base fully spawned and set-up so we can reset this. */
70
p_base.mainScript.$swapBase = false;
72
/* Get a unique name for the base.
73
* Maximum length (not including prefix) for the base's name is 16 characters.
74
* Fits perfectly into the mission screen title header.
76
this.ship.displayName = p_base.mainScript.$uniqueShipName(this.ship.name, 16);
78
if (!system.isInterstellarSpace) {
79
/* Point the docking bay in the general direction of the sun. */
80
vector = system.sun.position.subtract(this.ship.position).direction();
82
/* Point the docking bay in the general direction of the fake witchpoint. */
83
vector = p_base.mainScript.$witchpointBuoy.position.subtract(this.ship.position).direction();
86
/* Angle to the vector from current heading + about 1/8th turn. */
87
angle = this.ship.heading.angleTo(vector) + 0.707;
88
/* Cross vector for rotate. */
89
cross = this.ship.heading.cross(vector).direction();
90
/* Rotate the base by angle. */
91
this.ship.orientation = this.ship.orientation.rotate(cross, -angle);
93
/* Add some clutter within 20km around the base.
94
* 20 to 27 asteroids and 10 to 17 boulders
95
* - gives the miners something to do. (Also apparently any Thargoids!)
97
num = Math.floor(system.scrambledPseudoRandomNumber(p_base.mainScript.$salt) * 8) + 20;
98
system.addShips("jaguar_company_asteroid", num, this.ship.position, 20000);
99
num = Math.floor(system.scrambledPseudoRandomNumber(p_base.mainScript.$salt / 2) * 8) + 10;
100
system.addShips("jaguar_company_boulder", num, this.ship.position, 20000);
102
/* Reset the launch status of the buoy. */
103
p_base.mainScript.$buoyLaunched = false;
104
/* Miner has not launched. */
105
p_base.minerLaunched = false;
107
if (!system.shipsWithPrimaryRole("jaguar_company_patrol").length) {
108
/* Reset how many Jaguar Company patrol ships are in system. */
109
p_base.mainScript.$numPatrolShips = 0;
110
/* No patrol ships have launched. */
111
p_base.patrolShipsLaunched = 0;
112
/* Reset the fully launched status of the patrol ships. */
113
p_base.mainScript.$patrolShipsFullyLaunched = false;
115
/* Set how many Jaguar Company patrol ships are in system. */
116
p_base.mainScript.$numPatrolShips = system.shipsWithPrimaryRole("jaguar_company_patrol").length;
117
/* All patrol ships have launched. */
118
p_base.patrolShipsLaunched = p_base.mainScript.$numPatrolShips;
119
/* Set the fully launched status of the patrol ships. */
120
p_base.mainScript.$patrolShipsFullyLaunched = true;
124
/* Start up the timer to do some house keeping. */
125
this.$baseTimerReference = new Timer(this, this.$baseTimer, 5, 5);
128
/* Base was destroyed.
129
* Called after the script installed by $addFriendly in jaguar_company_attackers.js
132
* attacker - entity that caused the death.
133
* why - cause as a string.
135
this.shipDied = function (attacker, why) {
147
/* Stop warnings about anonymous local functions within loops.
148
* Used by 'system.filteredEntities'. Returns true for any valid entity.
150
function $validEntity(entity) {
151
return (entity && entity.isValid);
154
if (base.name === base.displayName) {
155
/* Died whilst being created. The base will not have had it's display name set up. */
156
mainScript = worldScripts["Jaguar Company"];
157
witchpointBuoy = mainScript.$witchpointBuoy;
158
mainPlanet = system.mainPlanet;
159
salt = mainScript.$salt;
162
/* Shift the base position if it is too close to any entity.
163
* If we happen to pick a new position that would collide with something already in the system
164
* then the loop will pick another position and so on.
165
* In practice the loop will only happen once as space is BIG.
168
/* Increase the salt. */
170
/* Place the base 0.1 to 0.3 units along the witchpoint -> main planet route. */
171
ratio = 0.1 + (system.scrambledPseudoRandomNumber(salt) * 0.2);
172
basePosition = Vector3D.interpolate(witchpointBuoy.position, mainPlanet.position, ratio);
173
/* Move it 4 to 6 times scanning range upwards with respect to the main planet's surface. */
174
ratio = (4 + (system.scrambledPseudoRandomNumber(salt) * 2)) * 25600;
175
mPovUp = mainPlanet.orientation.vectorUp();
176
base.position = basePosition.add(mPovUp.multiply(mainPlanet.radius + ratio));
177
/* Search for any entity intersecting this base within scanner range. */
178
entities = system.filteredEntities(this, $validEntity, base, 25600);
179
/* An empty array is what we are looking for. */
180
ok = !entities.length;
183
if (mainScript.$logging && mainScript.$logExtra) {
184
log(this.name, "shipDied::\n" +
185
"Base respawning: " + why + " whilst being created.\n" +
186
"* WP-Sun dot WP-MP: " +
187
(witchpointBuoy.position.subtract(system.sun.position).direction()
188
.dot(witchpointBuoy.position.subtract(mainPlanet.position).direction())) + "\n" +
189
"* Moved: " + (salt - mainScript.$salt) + " times.");
192
/* Spawn a new base. Update the public variable in the main script. */
193
mainScript.$jaguarCompanyBase = base.spawnOne("jaguar_company_base");
199
/* Base was removed by script. */
200
this.shipRemoved = function (suppressDeathEvent) {
201
if (suppressDeathEvent) {
205
/* Set this as no more ships will be launched. "Obvious cat is obvious!" */
206
worldScripts["Jaguar Company"].$patrolShipsFullyLaunched = true;
209
/* The base has just become invalid. */
210
this.entityDestroyed = function () {
211
/* Set this as no more ships will be launched. "Obvious cat is obvious!" */
212
worldScripts["Jaguar Company"].$patrolShipsFullyLaunched = true;
214
/* Stop and remove the timer. */
215
if (this.$baseTimerReference) {
216
if (this.$baseTimerReference.isRunning) {
217
this.$baseTimerReference.stop();
220
delete this.$baseTimerReference;
224
/* A ship has docked.
227
* whom - entity of the docked ship.
229
this.otherShipDocked = function (whom) {
230
if (whom.hasRole("jaguar_company_patrol")) {
231
/* Decrease the number of patrol ships that are launched. */
232
p_base.patrolShipsLaunched -= 1;
233
} else if (whom.hasRole("jaguar_company_miner")) {
234
/* Reset the launch status of the miner. */
235
p_base.mainScript.$minerLaunched = false;
239
/* A ship has launched.
242
* whom - entity of the launched ship.
244
this.stationLaunchedShip = function (whom) {
245
if (whom.hasRole("jaguar_company_patrol")) {
246
if (p_base.patrolShipsLaunched === 1) {
247
/* Initialise the route list with the default route. */
248
p_base.mainScript.$initRoute();
251
if (whom.script.name !== "jaguar_company_patrol.js") {
252
/* Remove the patrol ship. */
254
/* Decrease the number of patrol ships that are launched. */
255
p_base.patrolShipsLaunched -= 1;
257
if (p_base.logging && p_base.logExtra) {
258
log(this.name, "Script sanity check - fixed a patrol ship.");
262
if (p_base.patrolShipsLaunched !== p_base.mainScript.$maxPatrolShips) {
263
/* Launch another patrol ship. */
264
this.$launchJaguarCompanyPatrol();
266
/* All patrol ships are now fully launched. */
267
p_base.mainScript.$patrolShipsFullyLaunched = true;
269
} else if (whom.hasRole("jaguar_company_tug")) {
270
if (whom.script.name !== "jaguar_company_tug.js") {
271
/* Remove the tug. */
273
/* Reset the launch status of the buoy. */
274
p_base.mainScript.$buoyLaunched = false;
275
/* Launch another tug. */
276
this.$launchJaguarCompanyTug();
278
if (p_base.logging && p_base.logExtra) {
279
log(this.name, "Script sanity check - fixed the tug.");
282
} else if (whom.hasRole("jaguar_company_miner")) {
283
if (whom.script.name !== "jaguar_company_miner.js") {
284
/* Remove the miner. */
286
/* Reset the launch status of the miner. */
287
p_base.mainScript.$minerLaunched = false;
288
/* Launch another miner. */
289
this.ship.launchShipWithRole("jaguar_company_miner");
291
if (p_base.logging && p_base.logExtra) {
292
log(this.name, "Script sanity check - fixed the miner.");
298
/* Timer callback. */
300
/* Some OXP's dick around with the scanner colours. This will reset the base's scanner colour
301
* back to the station default of solid green if the player has helped out in combat with Jaguar Company.
303
* Starts the launch sequence for the patrol ships if needed.
305
* Checks the buoy and launches a tug if there isn't one. Resets the scanner colour as per the base.
306
* Swaps the buoy to 'no beacon' or 'beacon' dependent on the reputation mission variable.
308
* Called every 5 seconds.
310
this.$baseTimer = function () {
311
var base = this.ship,
318
/* Reset the base scanner colour. */
319
base.scannerDisplayColor1 = null;
320
base.scannerDisplayColor2 = null;
322
if (!p_base.patrolShipsLaunched) {
323
/* Start launching patrol ships. */
324
this.$launchJaguarCompanyPatrol();
327
if (p_base.patrolShipsLaunched !== p_base.mainScript.$maxPatrolShips) {
328
/* Reset the fully launched status of the patrol ships. */
329
p_base.mainScript.$patrolShipsFullyLaunched = false;
332
buoy = p_base.mainScript.$buoy;
334
if ((!buoy || !buoy.isValid) &&
335
!p_base.mainScript.$buoyLaunched && p_base.mainScript.$patrolShipsFullyLaunched) {
336
/* No buoys. Launch the tug to drop a buoy off. */
337
this.$launchJaguarCompanyTug();
342
if (buoy && buoy.isValid) {
343
/* Reset the buoy scanner colour. */
344
buoy.scannerDisplayColor1 = null;
345
buoy.scannerDisplayColor2 = null;
347
if (missionVariables.jaguar_company_reputation < p_base.mainScript.$reputationHelper) {
348
newBuoyRole = "jaguar_company_base_buoy_no_beacon";
350
newBuoyRole = "jaguar_company_base_buoy_beacon";
353
/* Check if the buoy already has the new role. */
354
if (!buoy.hasRole(newBuoyRole)) {
355
/* Copy some properties. */
356
position = buoy.position;
357
orientation = buoy.orientation;
358
/* Create a new buoy. */
359
newBuoy = buoy.spawnOne(newBuoyRole);
360
/* Remove the origial buoy quietly: don't trigger 'shipDied' in the ship script. */
362
/* Setup the new buoy with the original properties. */
363
newBuoy.position = position;
364
newBuoy.orientation = orientation;
365
/* Update the main script public variable. */
366
p_base.mainScript.$buoy = newBuoy;
371
/* Launch a patrol ship. */
372
this.$launchJaguarCompanyPatrol = function () {
373
if (p_base.logging && p_base.logExtra) {
374
log(this.name, "$launchJaguarCompanyPatrol::Launching patrol ship...");
377
p_base.patrolShipsLaunched += 1;
378
this.ship.launchShipWithRole("jaguar_company_patrol");
381
/* Launch the tug to drag the buoy into position. */
382
this.$launchJaguarCompanyTug = function () {
383
if (p_base.mainScript.$patrolShipsFullyLaunched &&
384
!p_base.mainScript.$buoyLaunched &&
385
(!p_base.mainScript.$buoy || !p_base.mainScript.$buoy.isValid)) {
386
/* Only one tug dragging a buoy at a time. Also no more than 1 buoy in system at a time.
387
* Also don't launch until all patrol ships have launched.
389
p_base.mainScript.$buoyLaunched = true;
390
this.ship.launchShipWithRole("jaguar_company_tug");
392
if (p_base.logging && p_base.logExtra) {
393
log(this.name, "$launchJaguarCompanyTug::Launching tug...");
400
/* Check if we need to launch a miner. Don't launch in interstellar space. */
401
this.$launchShip = function () {
402
if (!system.isInterstellarSpace &&
403
Math.random() < 0.05 &&
404
!p_base.minerLaunched &&
405
p_base.mainScript.$patrolShipsFullyLaunched) {
406
/* Only 1 miner at a time.
407
* Also don't launch until all patrol ships have launched.
409
p_base.minerLaunched = true;
410
this.ship.launchShipWithRole("jaguar_company_miner");
412
if (p_base.logging && p_base.logExtra) {
413
log(this.name, "$launchShip::Launching miner...");