1
/*jslint indent: 4, maxlen: 120, maxerr: 50, white: true, es5: true, undef: true, bitwise: true, regexp: true,
3
/*jshint es5: true, undef: true, bitwise: true, eqnull: true, noempty: true, eqeqeq: true, boss: true, loopfunc: true,
4
laxbreak: true, strict: true, curly: true */
5
/*global system, log, worldScripts, missionVariables, Timer, player */
9
* Copyright © 2012 Richard Thomas Harrison (Tricky)
11
* This work is licensed under the Creative Commons
12
* Attribution-Noncommercial-Share Alike 3.0 Unported License.
14
* To view a copy of this license, visit
15
* http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter
16
* to Creative Commons, 171 Second Street, Suite 300, San Francisco,
17
* California, 94105, USA.
19
* Ship related functions for the base AI.
25
/* Standard public variables for OXP scripts. */
26
this.name = "jaguar_company_base.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 Base.";
33
/* Private variable. */
36
/* Ship event callbacks. */
38
/* Initialise various variables on ship birth. */
39
this.shipSpawned = function () {
45
/* No longer needed after setting up. */
46
delete this.shipSpawned;
48
/* Initialise the p_base variable object.
49
* Encapsulates all private global data.
52
/* Cache the world scripts. */
53
mainScript : worldScripts["Jaguar Company"],
54
attackersScript : worldScripts["Jaguar Company Attackers"],
55
/* Local copies of the logging variables. */
56
logging : worldScripts["Jaguar Company"].$logging,
57
logExtra : worldScripts["Jaguar Company"].$logExtra
60
/* Register this base as a friendly. */
61
p_base.attackersScript.$addFriendly(this.ship);
63
if (p_base.mainScript.$swapBase) {
64
/* Swapping base roles. */
66
/* How many patrol ships have launched. */
67
p_base.patrolShipsLaunched = system.shipsWithPrimaryRole("jaguar_company_patrol").length;
68
/* Has the miner launched. */
69
p_base.minerLaunched = (system.shipsWithRole("jaguar_company_miner").length !== 0);
70
/* Base fully spawned and set-up so we can reset this. */
71
p_base.mainScript.$swapBase = false;
73
/* Get a unique name for the base.
74
* Maximum length (not including prefix) for the base's name is 16 characters.
75
* Fits perfectly into the mission screen title header.
77
this.ship.displayName = p_base.mainScript.$uniqueShipName(this.ship.name, 16);
79
if (!system.isInterstellarSpace) {
80
/* Point the docking bay in the general direction of the sun. */
81
vector = system.sun.position.subtract(this.ship.position).direction();
83
/* Point the docking bay in the general direction of the fake witchpoint. */
84
vector = p_base.mainScript.$witchpointBuoy.position.subtract(this.ship.position).direction();
87
/* Angle to the vector from current heading + about 1/8th turn. */
88
angle = this.ship.heading.angleTo(vector) + 0.707;
89
/* Cross vector for rotate. */
90
cross = this.ship.heading.cross(vector).direction();
91
/* Rotate the base by angle. */
92
this.ship.orientation = this.ship.orientation.rotate(cross, -angle);
94
/* Add some clutter within 20km around the base.
95
* 20 to 27 asteroids and 20 to 27 boulders
96
* - gives the miners something to do. (Also apparently any Thargoids!)
98
num = Math.floor(system.scrambledPseudoRandomNumber(p_base.mainScript.$salt) * 8) + 20;
99
system.addShips("jaguar_company_asteroid", num, this.ship.position, 20000);
100
num = Math.floor(system.scrambledPseudoRandomNumber(p_base.mainScript.$salt / 2) * 8) + 20;
101
system.addShips("jaguar_company_boulder", num, this.ship.position, 20000);
103
/* Reset the launch status of the buoy. */
104
p_base.mainScript.$buoyLaunched = false;
105
/* Miner has not launched. */
106
p_base.minerLaunched = false;
108
if (!system.shipsWithPrimaryRole("jaguar_company_patrol").length) {
109
/* Reset how many Jaguar Company patrol ships are in system. */
110
p_base.mainScript.$numPatrolShips = 0;
111
/* No patrol ships have launched. */
112
p_base.patrolShipsLaunched = 0;
113
/* Reset the fully launched status of the patrol ships. */
114
p_base.mainScript.$patrolShipsFullyLaunched = false;
116
/* Set how many Jaguar Company patrol ships are in system. */
117
p_base.mainScript.$numPatrolShips = system.shipsWithPrimaryRole("jaguar_company_patrol").length;
118
/* All patrol ships have launched. */
119
p_base.patrolShipsLaunched = p_base.mainScript.$numPatrolShips;
120
/* Set the fully launched status of the patrol ships. */
121
p_base.mainScript.$patrolShipsFullyLaunched = true;
125
/* Start up the timer to do some house keeping. */
126
this.$baseTimerReference = new Timer(this, this.$baseTimer, 5, 5);
129
/* Base was destroyed.
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");
198
/* Call common code used by all of Jaguar Company. */
199
worldScripts["Jaguar Company Attackers"].$shipDied(this.ship, attacker, why);
202
/* Base was removed by script. */
203
this.shipRemoved = function (suppressDeathEvent) {
204
if (suppressDeathEvent) {
208
/* Set this as no more ships will be launched. "Obvious cat is obvious!" */
209
worldScripts["Jaguar Company"].$patrolShipsFullyLaunched = true;
212
/* The base has just become invalid. */
213
this.entityDestroyed = function () {
214
/* Set this as no more ships will be launched. "Obvious cat is obvious!" */
215
worldScripts["Jaguar Company"].$patrolShipsFullyLaunched = true;
217
/* Stop and remove the timer. */
218
if (this.$baseTimerReference) {
219
if (this.$baseTimerReference.isRunning) {
220
this.$baseTimerReference.stop();
223
delete this.$baseTimerReference;
227
/* Someone is pinging us with their laser.
230
* attacker - entity of the ship that attacked.
232
this.shipBeingAttacked = function (attacker) {
233
/* Call common code used by all of Jaguar Company. */
234
p_base.attackersScript.$shipIsBeingAttacked(this.ship, attacker);
237
/* Someone has fired a missile at us.
240
* missile - missile entity.
241
* attacker - entity of the ship that attacked.
243
this.shipAttackedWithMissile = function (missile, attacker) {
244
/* Call common code used by all of Jaguar Company. */
245
p_base.attackersScript.$shipIsBeingAttackedWithMissile(this.ship, attacker);
248
/* We killed someone.
251
* target - entity of the destroyed target.
253
this.shipTargetDestroyed = function (target) {
254
if (target.primaryRole === "constrictor" &&
255
missionVariables.conhunt &&
256
missionVariables.conhunt === "STAGE_1") {
257
/* Just in case the base kills the constrictor, let's not break the mission for the player... */
258
missionVariables.conhunt = "CONSTRICTOR_DESTROYED";
260
player.credits += target.bounty;
261
player.consoleMessage(this.ship.displayName + " assisted in the death of " + target.name, 3);
262
player.consoleMessage(
263
this.ship.displayName + ": Commander " + player.name +
264
", you have the kill and bounty of " + target.bounty + "₢.", 3);
266
if (p_base.logging && p_base.logExtra) {
267
log(this.name, "shipTargetDestroyed::" +
268
this.ship.displayName + " killed - " + target.name + " : " + target.bounty);
273
/* A ship has docked.
276
* whom - entity of the docked ship.
278
this.otherShipDocked = function (whom) {
279
if (whom.hasRole("jaguar_company_patrol")) {
280
/* Decrease the number of patrol ships that are launched. */
281
p_base.patrolShipsLaunched -= 1;
282
} else if (whom.hasRole("jaguar_company_miner")) {
283
/* Reset the launch status of the miner. */
284
p_base.mainScript.$minerLaunched = false;
288
/* A ship has launched.
291
* whom - entity of the launched ship.
293
this.stationLaunchedShip = function (whom) {
294
if (whom.hasRole("jaguar_company_patrol")) {
295
if (p_base.patrolShipsLaunched === 1) {
296
/* Initialise the route list with the default route. */
297
p_base.mainScript.$initRoute();
300
if (whom.script.name !== "jaguar_company_patrol.js") {
301
/* Remove the patrol ship. */
303
/* Decrease the number of patrol ships that are launched. */
304
p_base.patrolShipsLaunched -= 1;
306
if (p_base.logging && p_base.logExtra) {
307
log(this.name, "Script sanity check - fixed a patrol ship.");
311
if (p_base.patrolShipsLaunched !== p_base.mainScript.$maxPatrolShips) {
312
/* Launch another patrol ship. */
313
this.$launchJaguarCompanyPatrol();
315
/* All patrol ships are now fully launched. */
316
p_base.mainScript.$patrolShipsFullyLaunched = true;
318
} else if (whom.hasRole("jaguar_company_tug")) {
319
if (whom.script.name !== "jaguar_company_tug.js") {
320
/* Remove the tug. */
322
/* Reset the launch status of the buoy. */
323
p_base.mainScript.$buoyLaunched = false;
324
/* Launch another tug. */
325
this.$launchJaguarCompanyTug();
327
if (p_base.logging && p_base.logExtra) {
328
log(this.name, "Script sanity check - fixed the tug.");
331
} else if (whom.hasRole("jaguar_company_miner")) {
332
if (whom.script.name !== "jaguar_company_miner.js") {
333
/* Remove the miner. */
335
/* Reset the launch status of the miner. */
336
p_base.mainScript.$minerLaunched = false;
337
/* Launch another miner. */
338
this.ship.launchShipWithRole("jaguar_company_miner");
340
if (p_base.logging && p_base.logExtra) {
341
log(this.name, "Script sanity check - fixed the miner.");
347
/* Timer callback. */
349
/* Some OXP's dick around with the scanner colours. This will reset the base's scanner colour
350
* back to the station default of solid green if the player has helped out in combat with Jaguar Company.
352
* Starts the launch sequence for the patrol ships if needed.
354
* Checks the buoy and launches a tug if there isn't one. Resets the scanner colour as per the base.
355
* Swaps the buoy to 'no beacon' or 'beacon' dependent on the reputation mission variable.
357
* Called every 5 seconds.
359
this.$baseTimer = function () {
360
var base = this.ship,
367
/* Reset the base scanner colour. */
368
base.scannerDisplayColor1 = null;
369
base.scannerDisplayColor2 = null;
371
if (!p_base.patrolShipsLaunched) {
372
/* Start launching patrol ships. */
373
this.$launchJaguarCompanyPatrol();
376
if (p_base.patrolShipsLaunched !== p_base.mainScript.$maxPatrolShips) {
377
/* Reset the fully launched status of the patrol ships. */
378
p_base.mainScript.$patrolShipsFullyLaunched = false;
381
buoy = p_base.mainScript.$buoy;
383
if ((!buoy || !buoy.isValid) &&
384
!p_base.mainScript.$buoyLaunched && p_base.mainScript.$patrolShipsFullyLaunched) {
385
/* No buoys. Launch the tug to drop a buoy off. */
386
this.$launchJaguarCompanyTug();
391
if (buoy && buoy.isValid) {
392
/* Reset the buoy scanner colour. */
393
buoy.scannerDisplayColor1 = null;
394
buoy.scannerDisplayColor2 = null;
396
if (missionVariables.jaguar_company_reputation < p_base.mainScript.$reputationHelper) {
397
newBuoyRole = "jaguar_company_base_buoy_no_beacon";
399
newBuoyRole = "jaguar_company_base_buoy_beacon";
402
/* Check if the buoy already has the new role. */
403
if (!buoy.hasRole(newBuoyRole)) {
404
/* Copy some properties. */
405
position = buoy.position;
406
orientation = buoy.orientation;
407
/* Create a new buoy. */
408
newBuoy = buoy.spawnOne(newBuoyRole);
409
/* Remove the origial buoy quietly: don't trigger 'shipDied' in the ship script. */
411
/* Setup the new buoy with the original properties. */
412
newBuoy.position = position;
413
newBuoy.orientation = orientation;
414
/* Update the main script public variable. */
415
p_base.mainScript.$buoy = newBuoy;
420
/* Launch a patrol ship. */
421
this.$launchJaguarCompanyPatrol = function () {
422
if (p_base.logging && p_base.logExtra) {
423
log(this.name, "$launchJaguarCompanyPatrol::Launching patrol ship...");
426
p_base.patrolShipsLaunched += 1;
427
this.ship.launchShipWithRole("jaguar_company_patrol");
430
/* Launch the tug to drag the buoy into position. */
431
this.$launchJaguarCompanyTug = function () {
432
if (p_base.mainScript.$patrolShipsFullyLaunched &&
433
!p_base.mainScript.$buoyLaunched &&
434
(!p_base.mainScript.$buoy || !p_base.mainScript.$buoy.isValid)) {
435
/* Only one tug dragging a buoy at a time. Also no more than 1 buoy in system at a time.
436
* Also don't launch until all patrol ships have launched.
438
p_base.mainScript.$buoyLaunched = true;
439
this.ship.launchShipWithRole("jaguar_company_tug");
441
if (p_base.logging && p_base.logExtra) {
442
log(this.name, "$launchJaguarCompanyTug::Launching tug...");
449
/* Check if we need to launch a miner. Don't launch in interstellar space. */
450
this.$launchShip = function () {
451
if (!system.isInterstellarSpace &&
452
Math.random() < 0.05 &&
453
!p_base.minerLaunched &&
454
p_base.mainScript.$patrolShipsFullyLaunched) {
455
/* Only 1 miner at a time.
456
* Also don't launch until all patrol ships have launched.
458
p_base.minerLaunched = true;
459
this.ship.launchShipWithRole("jaguar_company_miner");
461
if (p_base.logging && p_base.logExtra) {
462
log(this.name, "$launchShip::Launching miner...");
467
/* Check for any previous attackers that have run away. */
468
this.$scanForAttackers = function () {
469
/* Call common code used by all of Jaguar Company. */
470
p_base.attackersScript.$scanForAttackers(this.ship);
473
/* Checks the current target to make sure it is still valid. */
474
this.$checkTargetIsValid = function () {
475
/* Call common code used by all of Jaguar Company. */
476
p_base.attackersScript.$checkTargetIsValid(this.ship);
479
/* This does something similar to the groupAttackTarget AI command. */
480
this.$performJaguarCompanyAttackTarget = function () {
481
/* Call common code used by all of Jaguar Company. */
482
p_base.attackersScript.$performAttackTarget(this.ship);